bf1d82
bf1d82
#include <streambuf></streambuf>
bf1d82
bf1d82
#include <qstandardpaths></qstandardpaths>
bf1d82
bf1d82
#include "tfilepath_io.h"
bf1d82
#include "timage_io.h"
bf1d82
#include "trop.h"
bf1d82
#include "tsystem.h"
bf1d82
#include "tvectorimage.h"
bf1d82
#include "tpixelutils.h"
bf1d82
#include "toonz/toonzscene.h"
bf1d82
bf1d82
#include "toonz/mypaintbrushstyle.h"
bf1d82
manongjohn 2932f5
#include <qdebug></qdebug>
manongjohn 2932f5
manongjohn 2932f5
#include <sstream></sstream>
bf1d82
bf1d82
//*************************************************************************************
bf1d82
//    TMyPaintBrushStyle  implementation
bf1d82
//*************************************************************************************
bf1d82
manongjohn 2932f5
TMyPaintBrushStyle::TMyPaintBrushStyle() {}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
bf1d82
TMyPaintBrushStyle::TMyPaintBrushStyle(const TFilePath &path) {
bf1d82
  loadBrush(path);
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
TMyPaintBrushStyle::TMyPaintBrushStyle(const TMyPaintBrushStyle &other)
manongjohn 2932f5
    : TColorStyle(other)
manongjohn 2932f5
    , m_path(other.m_path)
manongjohn 2932f5
    , m_fullpath(other.m_fullpath)
manongjohn 2932f5
    , m_brushOriginal(other.m_brushOriginal)
manongjohn 2932f5
    , m_brushModified(other.m_brushModified)
manongjohn 2932f5
    , m_preview(other.m_preview)
manongjohn 2932f5
    , m_color(other.m_color)
manongjohn 2932f5
    , m_baseValues(other.m_baseValues) {}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
TMyPaintBrushStyle::~TMyPaintBrushStyle() {}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
justburner 981d46
TColorStyle *TMyPaintBrushStyle::clone(std::string brushIdName) const {
justburner 981d46
  TMyPaintBrushStyle *style = new TMyPaintBrushStyle(*this);
justburner 981d46
  style->loadBrush(TFilePath(getBrushIdNameParam(brushIdName)));
justburner 981d46
  return style;
justburner 981d46
}
justburner 981d46
justburner 981d46
//-----------------------------------------------------------------------------
justburner 981d46
manongjohn 2932f5
TColorStyle &TMyPaintBrushStyle::copy(const TColorStyle &other) {
bf1d82
  const TMyPaintBrushStyle *otherBrushStyle =
manongjohn 2932f5
      dynamic_cast<const *="" tmypaintbrushstyle="">(&other);</const>
bf1d82
  if (otherBrushStyle) {
bf1d82
    m_path          = otherBrushStyle->m_path;
bf1d82
    m_fullpath      = otherBrushStyle->m_fullpath;
bf1d82
    m_brushOriginal = otherBrushStyle->m_brushOriginal;
bf1d82
    m_brushModified = otherBrushStyle->m_brushModified;
bf1d82
    m_preview       = otherBrushStyle->m_preview;
bf1d82
    m_baseValues    = otherBrushStyle->m_baseValues;
bf1d82
  }
bf1d82
  assignBlend(other, other, 0.0);
bf1d82
  return *this;
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
QString TMyPaintBrushStyle::getDescription() const {
manongjohn 2932f5
  return "MyPaintBrushStyle";
manongjohn 2932f5
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
justburner 981d46
std::string TMyPaintBrushStyle::getBrushIdName() const {
justburner 981d46
  std::wstring ws = m_path.getWideString();
justburner 981d46
  const std::string s(ws.begin(), ws.end());
justburner 981d46
  return "MyPaintBrushStyle:" + s;
justburner 981d46
}
justburner 981d46
justburner 981d46
//-----------------------------------------------------------------------------
justburner 981d46
manongjohn 2932f5
std::string TMyPaintBrushStyle::getBrushType() { return "myb"; }
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
bf1d82
TFilePathSet TMyPaintBrushStyle::getBrushesDirs() {
bf1d82
  TFilePathSet paths;
bf1d82
  paths.push_back(m_libraryDir + "mypaint brushes");
manongjohn 2932f5
  QStringList genericLocations =
manongjohn 2932f5
      QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
manongjohn 2932f5
  for (QStringList::iterator i = genericLocations.begin();
manongjohn 2932f5
       i != genericLocations.end(); ++i)
bf1d82
    paths.push_back(TFilePath(*i) + "mypaint" + "brushes");
bf1d82
  return paths;
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
bf1d82
TFilePath TMyPaintBrushStyle::decodePath(const TFilePath &path) const {
manongjohn 2932f5
  if (path.isAbsolute()) return path;
bf1d82
bf1d82
  if (m_currentScene) {
bf1d82
    TFilePath p = m_currentScene->decodeFilePath(path);
bf1d82
    TFileStatus fs(p);
manongjohn 2932f5
    if (fs.doesExist() && !fs.isDirectory()) return p;
bf1d82
  }
bf1d82
bf1d82
  TFilePathSet paths = getBrushesDirs();
manongjohn 2932f5
  for (TFilePathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
bf1d82
    TFilePath p = *i + path;
bf1d82
    TFileStatus fs(p);
manongjohn 2932f5
    if (fs.doesExist() && !fs.isDirectory()) return p;
bf1d82
  }
bf1d82
bf1d82
  return path;
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
Rozhuk Ivan 823a31
static std::string mybToVersion3(std::string origStr) {
manongjohn 2932f5
  std::string outStr   = "";
manongjohn 2932f5
  std::string comment  = "";
manongjohn 2932f5
  bool settingsStarted = false;
manongjohn 2932f5
manongjohn 2932f5
  std::stringstream strstream(origStr);
manongjohn 2932f5
manongjohn 2932f5
  outStr += "{\n";
manongjohn 2932f5
  for (std::string line; std::getline(strstream, line);) {
manongjohn 2932f5
    std::replace(line.begin(), line.end(), '\r', ' ');
manongjohn 2932f5
    if (line.find("version 2") != std::string::npos)
manongjohn 2932f5
      continue;  // Ignore version.  We'll add version back later as version 3
manongjohn 2932f5
manongjohn 2932f5
    if (line[0] == '#') {
manongjohn 2932f5
      comment = comment + line;
manongjohn 2932f5
      continue;
manongjohn 2932f5
    }
manongjohn 2932f5
manongjohn 2932f5
    if (!settingsStarted) {
manongjohn 2932f5
      settingsStarted = true;
manongjohn 2932f5
      outStr += "    \"comment\": \"" + comment + "\",\n";
manongjohn 2932f5
      outStr += "    \"group\": \"\",\n";
manongjohn 2932f5
      outStr += "    \"parent_brush_name\": \"\",\n";
manongjohn 2932f5
      outStr += "    \"settings\": {\n";
manongjohn 2932f5
    } else
manongjohn 2932f5
      outStr += ",\n";
manongjohn 2932f5
manongjohn 2932f5
    int startPos = 0;
manongjohn 2932f5
    int pipe     = line.find("|");
manongjohn 2932f5
manongjohn 2932f5
    std::string settingInfo = line.substr(startPos, pipe);
manongjohn 2932f5
    std::string setting     = settingInfo.substr(startPos, line.find(" "));
manongjohn 2932f5
    std::string baseValue =
manongjohn 2932f5
        settingInfo.substr(setting.length(), settingInfo.find_last_not_of(" "));
manongjohn 2932f5
    outStr += "        \"" + setting + "\": {\n";
manongjohn 2932f5
    outStr += "            \"base_value\": " + baseValue + ",\n";
manongjohn 2932f5
    if (pipe == std::string::npos)
manongjohn 2932f5
      outStr += "            \"inputs\": {}";
manongjohn 2932f5
    else {
manongjohn 2932f5
      outStr += "            \"inputs\": {\n";
manongjohn 2932f5
      while (pipe != line.length()) {
manongjohn 2932f5
        if (startPos > 0) outStr += ",\n";
shun-iwasawa c18bfa
        startPos = pipe + 1;
shun-iwasawa c18bfa
        pipe     = line.find("|", startPos);
manongjohn 2932f5
        if (pipe == std::string::npos) pipe = line.length();
manongjohn 2932f5
        settingInfo      = line.substr(startPos, pipe - startPos);
manongjohn 2932f5
        int firstCharPos = settingInfo.find_first_not_of(" ");
manongjohn 2932f5
        setting          = settingInfo.substr(firstCharPos,
manongjohn 2932f5
                                     settingInfo.find(" ", firstCharPos) - 1);
manongjohn 2932f5
        outStr += "                \"" + setting + "\": [\n";
manongjohn 2932f5
        firstCharPos = settingInfo.find_first_not_of(" ", setting.length() + 1);
manongjohn 2932f5
        baseValue    = settingInfo.substr(firstCharPos, pipe - startPos);
manongjohn 2932f5
        int comma    = baseValue.find(", ");
manongjohn 2932f5
        if (comma == std::string::npos) comma = baseValue.length();
shun-iwasawa c18bfa
        std::string value = baseValue.substr(0, comma);
manongjohn 2932f5
        std::replace(value.begin(), value.end(), '(', '[');
manongjohn 2932f5
        std::replace(value.begin(), value.end(), ')', ']');
manongjohn 2932f5
        std::replace(value.begin(), value.end(), ' ', ',');
manongjohn 2932f5
        outStr += "                    " + value;
manongjohn 2932f5
        int prevComma;
manongjohn 2932f5
        while (comma != baseValue.length()) {
manongjohn 2932f5
          outStr += ",\n";
manongjohn 2932f5
          prevComma = comma + 2;
manongjohn 2932f5
          comma     = baseValue.find(", ", prevComma);
manongjohn 2932f5
          if (comma == std::string::npos) comma = baseValue.length();
manongjohn 2932f5
          value = baseValue.substr(prevComma, comma - prevComma);
manongjohn 2932f5
          std::replace(value.begin(), value.end(), '(', '[');
manongjohn 2932f5
          std::replace(value.begin(), value.end(), ')', ']');
manongjohn 2932f5
          std::replace(value.begin(), value.end(), ' ', ',');
manongjohn 2932f5
          outStr += "                    " + value;
manongjohn 2932f5
        }
manongjohn 2932f5
        outStr += "\n                ]";  // Ends Input setting
manongjohn 2932f5
      }
manongjohn 2932f5
      outStr += "\n            }";  // End Inputs
manongjohn 2932f5
    }
manongjohn 2932f5
    outStr += "\n        }";  // End Setting
manongjohn 2932f5
  }
manongjohn 2932f5
  outStr += "\n";
manongjohn 2932f5
manongjohn 2932f5
  if (settingsStarted) {
manongjohn 2932f5
    outStr += "    },\n";  // End Settings
manongjohn 2932f5
    outStr += "    \"version\": 3\n";
manongjohn 2932f5
  }
manongjohn 2932f5
manongjohn 2932f5
  outStr += "}";  // Ends file
manongjohn 2932f5
  return outStr;
manongjohn 2932f5
}
bf1d82
bf1d82
void TMyPaintBrushStyle::loadBrush(const TFilePath &path) {
manongjohn 2932f5
  m_path     = path;
bf1d82
  m_fullpath = decodePath(path);
bf1d82
  m_brushOriginal.fromDefaults();
bf1d82
bf1d82
  Tifstream is(m_fullpath);
bf1d82
  if (is) {
bf1d82
    std::string str;
manongjohn 2932f5
    str.assign(std::istreambuf_iterator<char>(is),</char>
manongjohn 2932f5
               std::istreambuf_iterator<char>());</char>
manongjohn 2932f5
    if (str.find("version 2") != std::string::npos) str = mybToVersion3(str);
bf1d82
    m_brushOriginal.fromString(str);
bf1d82
  }
bf1d82
bf1d82
  m_brushModified = m_brushOriginal;
bf1d82
  std::map<mypaintbrushsetting, float=""> baseValuesCopy;</mypaintbrushsetting,>
bf1d82
  baseValuesCopy.swap(m_baseValues);
manongjohn 2932f5
  for (std::map<mypaintbrushsetting, float="">::const_iterator i =</mypaintbrushsetting,>
manongjohn 2932f5
           baseValuesCopy.begin();
manongjohn 2932f5
       i != baseValuesCopy.end(); ++i)
bf1d82
    setBaseValue(i->first, i->second);
bf1d82
manongjohn 2932f5
  TFilePath preview_path =
manongjohn 2932f5
      m_fullpath.getParentDir() + (m_fullpath.getWideName() + L"_prev.png");
bf1d82
  TImageReader::load(preview_path, m_preview);
bf1d82
bf1d82
  invalidateIcon();
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
void TMyPaintBrushStyle::setBaseValue(MyPaintBrushSetting id, bool enable,
manongjohn 2932f5
                                      float value) {
bf1d82
  float def = m_brushOriginal.getBaseValue(id);
bf1d82
  if (enable && fabsf(value - def) > 0.01) {
bf1d82
    m_baseValues[id] = value;
bf1d82
    m_brushModified.setBaseValue(id, value);
bf1d82
  } else {
bf1d82
    m_baseValues.erase(id);
bf1d82
    m_brushModified.setBaseValue(id, def);
bf1d82
  }
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
bf1d82
void TMyPaintBrushStyle::resetBaseValues() {
manongjohn 2932f5
  for (int i = 0; i < MYPAINT_BRUSH_SETTINGS_COUNT; ++i)
bf1d82
    setBaseValueEnabled((MyPaintBrushSetting)i, false);
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
bf1d82
void TMyPaintBrushStyle::makeIcon(const TDimension &d) {
manongjohn 2932f5
  TFilePath path =
manongjohn 2932f5
      m_fullpath.getParentDir() + (m_fullpath.getWideName() + L"_prev.png");
shun-iwasawa c18bfa
  TPointD offset(0, 0);
bf1d82
  if (!m_preview) {
bf1d82
    m_icon = TRaster32P(d);
bf1d82
    m_icon->fill(TPixel32::Red);
manongjohn 2932f5
  } else if (m_preview->getSize() == d) {
bf1d82
    m_icon = m_preview;
bf1d82
  } else {
shun-iwasawa c18bfa
    m_icon = TRaster32P(d);
shun-iwasawa c18bfa
    if (d.lx != d.ly) {
shun-iwasawa c18bfa
      TPixel32 col = getMainColor();
shun-iwasawa c18bfa
      if (col.m == 255)
shun-iwasawa c18bfa
        m_icon->fill(col);
shun-iwasawa c18bfa
      else {
shun-iwasawa c18bfa
        TRaster32P fg(d);
shun-iwasawa c18bfa
        fg->fill(premultiply(col));
shun-iwasawa c18bfa
        TRop::checkBoard(m_icon, TPixel32::Black, TPixel32::White,
shun-iwasawa c18bfa
                         TDimensionD(6, 6), TPointD());
shun-iwasawa c18bfa
        TRop::over(m_icon, fg);
shun-iwasawa c18bfa
      }
shun-iwasawa c18bfa
    }
shun-iwasawa c18bfa
    double sx    = (double)d.lx / (double)m_preview->getLx();
shun-iwasawa c18bfa
    double sy    = (double)d.ly / (double)m_preview->getLy();
shun-iwasawa c18bfa
    double scale = std::min(sx, sy);
manongjohn 1b1183
    TRaster32P resamplePreview(m_preview->getLx(), m_preview->getLy());
manongjohn 1b1183
    TRop::resample(resamplePreview, m_preview, TScale(scale),
manongjohn 1b1183
                   TRop::ResampleFilterType::Hamming3);
manongjohn 1b1183
    TRop::over(m_icon, resamplePreview);
bf1d82
  }
bf1d82
bf1d82
  // paint color marker
manongjohn 1b1183
  // Only show color marker when the icon size is 22x22
manongjohn 1b1183
  if (d.lx == d.ly && d.lx <= 22) {
shun-iwasawa c18bfa
    int size       = std::min(1 + std::min(d.lx, d.ly) * 2 / 3,
manongjohn 2932f5
                        1 + std::max(d.lx, d.ly) / 2);
bf1d82
    TPixel32 color = getMainColor();
shun-iwasawa c18bfa
    color.m        = 255;  // show full opac color
manongjohn 2932f5
    for (int y = 0; y < size; ++y) {
shun-iwasawa c18bfa
      TPixel32 *p    = m_icon->pixels(d.ly - y - 1);
shun-iwasawa c18bfa
      TPixel32 *endp = p + size - y - 1;
manongjohn 2932f5
      for (; p != endp; ++p) *p = color;
shun-iwasawa c18bfa
      *p = blend(*p, color, 0.5);
bf1d82
    }
bf1d82
  }
bf1d82
}
bf1d82
bf1d82
//------------------------------------------------------------
bf1d82
bf1d82
void TMyPaintBrushStyle::loadData(TInputStreamInterface &is) {
bf1d82
  std::string path;
bf1d82
  is >> path;
bf1d82
  is >> m_color;
bf1d82
  loadBrush(TFilePath(path));
bf1d82
bf1d82
  int baseSettingsCount = 0;
bf1d82
  is >> baseSettingsCount;
manongjohn 2932f5
  for (int i = 0; i < baseSettingsCount; ++i) {
bf1d82
    std::string key;
manongjohn 2932f5
    double value    = 0.0;
bf1d82
    int inputsCount = 0;
bf1d82
    is >> key;
bf1d82
    is >> value;
bf1d82
    const mypaint::Setting *setting = mypaint::Setting::findByKey(key);
bf1d82
    if (setting) setBaseValue(setting->id, value);
bf1d82
  }
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
bf1d82
void TMyPaintBrushStyle::saveData(TOutputStreamInterface &os) const {
bf1d82
  std::wstring wstr = m_path.getWideString();
bf1d82
  std::string str;
bf1d82
  str.assign(wstr.begin(), wstr.end());
bf1d82
  os << str;
bf1d82
  os << m_color;
bf1d82
bf1d82
  os << (int)m_baseValues.size();
manongjohn 2932f5
  for (std::map<mypaintbrushsetting, float="">::const_iterator i =</mypaintbrushsetting,>
manongjohn 2932f5
           m_baseValues.begin();
manongjohn 2932f5
       i != m_baseValues.end(); ++i) {
bf1d82
    os << mypaint::Setting::byId(i->first).key;
bf1d82
    os << (double)i->second;
bf1d82
  }
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
int TMyPaintBrushStyle::getParamCount() const {
manongjohn 2932f5
  return MYPAINT_BRUSH_SETTINGS_COUNT;
manongjohn 2932f5
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
QString TMyPaintBrushStyle::getParamNames(int index) const {
manongjohn 2932f5
  return QString::fromUtf8(
manongjohn 2932f5
      mypaint::Setting::byId((MyPaintBrushSetting)index).name.c_str());
manongjohn 2932f5
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
TColorStyle::ParamType TMyPaintBrushStyle::getParamType(int index) const {
manongjohn 2932f5
  return DOUBLE;
manongjohn 2932f5
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
bool TMyPaintBrushStyle::hasParamDefault(int index) const { return true; }
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
void TMyPaintBrushStyle::setParamDefault(int index) {
manongjohn 2932f5
  setBaseValueEnabled((MyPaintBrushSetting)index, false);
manongjohn 2932f5
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
bool TMyPaintBrushStyle::isParamDefault(int index) const {
manongjohn 2932f5
  return getBaseValueEnabled((MyPaintBrushSetting)index);
manongjohn 2932f5
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
void TMyPaintBrushStyle::getParamRange(int index, double &min,
manongjohn 2932f5
                                       double &max) const {
manongjohn 2932f5
  const mypaint::Setting &setting =
manongjohn 2932f5
      mypaint::Setting::byId((MyPaintBrushSetting)index);
bf1d82
  min = setting.min;
bf1d82
  max = setting.max;
bf1d82
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
void TMyPaintBrushStyle::setParamValue(int index, double value) {
manongjohn 2932f5
  setBaseValue((MyPaintBrushSetting)index, value);
manongjohn 2932f5
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
manongjohn 2932f5
double TMyPaintBrushStyle::getParamValue(double_tag, int index) const {
manongjohn 2932f5
  return getBaseValue((MyPaintBrushSetting)index);
manongjohn 2932f5
}
bf1d82
bf1d82
//-----------------------------------------------------------------------------
bf1d82
bf1d82
namespace {
manongjohn 2932f5
TColorStyle::Declaration mypaintBrushStyle(new TMyPaintBrushStyle());
bf1d82
}