bf1d82
#pragma once
bf1d82
bf1d82
#ifndef MYPAINT_HPP
bf1d82
#define MYPAINT_HPP
bf1d82
bf1d82
#include <cmath></cmath>
bf1d82
#include <algorithm></algorithm>
bf1d82
#include <string></string>
bf1d82
bf1d82
extern "C" {
bf1d82
  #include <mypaint-brush.h></mypaint-brush.h>
bf1d82
  #include <mypaint-surface.h></mypaint-surface.h>
bf1d82
  #include <mypaint-brush-settings.h></mypaint-brush-settings.h>
bf1d82
}
bf1d82
bf1d82
namespace mypaint {
bf1d82
  class Brush;
bf1d82
bf1d82
  //=======================================================
bf1d82
  //
bf1d82
  // Dab
bf1d82
  //
bf1d82
  //=======================================================
bf1d82
bf1d82
  class Dab {
bf1d82
  public:
bf1d82
    float x;
bf1d82
    float y;
bf1d82
    float radius;
bf1d82
    float colorR;
bf1d82
    float colorG;
bf1d82
    float colorB;
bf1d82
    float opaque;
bf1d82
    float hardness;
bf1d82
    float alphaEraser;
bf1d82
    float aspectRatio;
bf1d82
    float angle;
bf1d82
    float lockAlpha;
bf1d82
    float colorize;
bf1d82
bf1d82
    Dab():
bf1d82
      x(), y(), radius(),
bf1d82
      colorR(), colorG(), colorB(),
bf1d82
      opaque(), hardness(), alphaEraser(),
bf1d82
      aspectRatio(), angle(),
bf1d82
      lockAlpha(), colorize()
bf1d82
      { }
bf1d82
bf1d82
    Dab(
bf1d82
      float x, float y, float radius,
bf1d82
      float colorR = 0.f, float colorG = 0.f, float colorB = 0.f,
bf1d82
      float opaque = 1.f, float hardness = 0.5f, float alphaEraser = 1.f,
bf1d82
      float aspectRatio = 1.f, float angle = 0.f,
bf1d82
      float lockAlpha = 0.f, float colorize = 0.f
bf1d82
    ):
bf1d82
      x(x), y(y), radius(radius),
bf1d82
      colorR(colorR), colorG(colorG), colorB(colorB),
bf1d82
      opaque(opaque), hardness(hardness), alphaEraser(alphaEraser),
bf1d82
      aspectRatio(aspectRatio), angle(angle),
bf1d82
      lockAlpha(lockAlpha), colorize(lockAlpha)
bf1d82
      { }
bf1d82
bf1d82
    void clamp() {
bf1d82
      radius      = fabsf(radius);
bf1d82
      colorR      = std::min(std::max(colorR,      0.f), 1.f);
bf1d82
      colorG      = std::min(std::max(colorG,      0.f), 1.f);
bf1d82
      colorB      = std::min(std::max(colorB,      0.f), 1.f);
bf1d82
      opaque      = std::min(std::max(opaque,      0.f), 1.f);
bf1d82
      hardness    = std::min(std::max(hardness,    0.f), 1.f);
bf1d82
      alphaEraser = std::min(std::max(alphaEraser, 0.f), 1.f);
bf1d82
      aspectRatio = std::max(aspectRatio, 1.f);
bf1d82
      lockAlpha   = std::min(std::max(lockAlpha,   0.f), 1.f);
bf1d82
      colorize    = std::min(std::max(colorize,    0.f), 1.f);
bf1d82
    }
bf1d82
bf1d82
    Dab getClamped() const
bf1d82
      { Dab dab(*this); dab.clamp(); return dab; }
bf1d82
  };
bf1d82
bf1d82
bf1d82
  //=======================================================
bf1d82
  //
bf1d82
  // Surface
bf1d82
  //
bf1d82
  //=======================================================
bf1d82
bf1d82
  class Surface {
bf1d82
    friend class Brush;
bf1d82
bf1d82
    struct InternalSurface: public MyPaintSurface {
bf1d82
      Surface *m_owner;
bf1d82
    };
bf1d82
bf1d82
    InternalSurface m_surface;
bf1d82
bf1d82
    static int internalDrawDab(
bf1d82
        MyPaintSurface *self,
bf1d82
        float x, float y, float radius,
bf1d82
        float colorR, float colorG, float colorB,
bf1d82
        float opaque, float hardness, float alphaEraser,
bf1d82
        float aspectRatio, float angle,
bf1d82
        float lockAlpha, float colorize )
bf1d82
    {
bf1d82
      return static_cast<internalsurface*>(self)->m_owner->drawDab( Dab(</internalsurface*>
bf1d82
        x, y, radius,
bf1d82
        colorR, colorG, colorB,
bf1d82
        opaque, hardness, alphaEraser,
bf1d82
        aspectRatio, angle,
bf1d82
        lockAlpha, colorize ));
bf1d82
    }
bf1d82
bf1d82
    static void internalGetColor(
bf1d82
        MyPaintSurface *self,
bf1d82
        float x, float y, float radius,
bf1d82
        float *colorR, float *colorG, float *colorB, float *colorA )
bf1d82
    {
bf1d82
      static_cast<internalsurface*>(self)->m_owner->getColor(</internalsurface*>
bf1d82
        x, y,
bf1d82
        radius,
bf1d82
        *colorR, *colorG, *colorB, *colorA);
bf1d82
    }
bf1d82
bf1d82
  public:
bf1d82
    Surface():
bf1d82
      m_surface()
bf1d82
    {
bf1d82
      m_surface.m_owner = this;
bf1d82
      m_surface.draw_dab = internalDrawDab;
bf1d82
      m_surface.get_color = internalGetColor;
bf1d82
    }
bf1d82
bf1d82
    virtual ~Surface() { }
bf1d82
bf1d82
    virtual bool getColor(
bf1d82
        float x, float y, float radius,
bf1d82
        float &colorR, float &colorG, float &colorB, float &colorA ) = 0;
bf1d82
bf1d82
    virtual bool drawDab(const Dab &dab) = 0;
bf1d82
  };
bf1d82
bf1d82
  //=======================================================
bf1d82
  //
bf1d82
  // Brush
bf1d82
  //
bf1d82
  //=======================================================
bf1d82
bf1d82
  class Brush {
bf1d82
    MyPaintBrush *m_brush;
bf1d82
bf1d82
  public:
bf1d82
    Brush():
bf1d82
      m_brush(mypaint_brush_new())
bf1d82
    { fromDefaults(); }
bf1d82
bf1d82
    Brush(const Brush &other):
bf1d82
      m_brush(mypaint_brush_new())
bf1d82
    { fromBrush(other); }
bf1d82
bf1d82
    ~Brush()
bf1d82
    { mypaint_brush_unref(m_brush); }
bf1d82
bf1d82
    Brush& operator= (const Brush &other) {
bf1d82
      fromBrush(other);
bf1d82
      return *this;
bf1d82
    }
bf1d82
bf1d82
    void reset()
bf1d82
    { mypaint_brush_reset(m_brush); }
bf1d82
bf1d82
    void newStroke()
bf1d82
    { mypaint_brush_new_stroke(m_brush); }
bf1d82
bf1d82
    int strokeTo(Surface &surface, float x, float y,
bf1d82
                  float pressure, float xtilt, float ytilt, double dtime)
bf1d82
    {
bf1d82
      return mypaint_brush_stroke_to(m_brush, &surface.m_surface,
bf1d82
                                     x, y, pressure, xtilt, ytilt, dtime);
bf1d82
    }
bf1d82
bf1d82
    void setBaseValue(MyPaintBrushSetting id, float value)
bf1d82
    { mypaint_brush_set_base_value(m_brush, id, value); }
bf1d82
bf1d82
    float getBaseValue(MyPaintBrushSetting id) const
bf1d82
    { return mypaint_brush_get_base_value(m_brush, id); }
bf1d82
bf1d82
    bool isConstant(MyPaintBrushSetting id) const
bf1d82
    { return mypaint_brush_is_constant(m_brush, id); }
bf1d82
bf1d82
    int getInputsUsedN(MyPaintBrushSetting id) const
bf1d82
    { return mypaint_brush_get_inputs_used_n(m_brush, id); }
bf1d82
bf1d82
    void setMappingN(MyPaintBrushSetting id, MyPaintBrushInput input, int n)
bf1d82
    { mypaint_brush_set_mapping_n(m_brush, id, input, n); }
bf1d82
bf1d82
    int getMappingN(MyPaintBrushSetting id, MyPaintBrushInput input) const
bf1d82
    { return mypaint_brush_get_mapping_n(m_brush, id, input); }
bf1d82
bf1d82
    void setMappingPoint(MyPaintBrushSetting id, MyPaintBrushInput input, int index, float x, float y)
bf1d82
    { mypaint_brush_set_mapping_point(m_brush, id, input, index, x, y); }
bf1d82
bf1d82
    void getMappingPoint(MyPaintBrushSetting id, MyPaintBrushInput input, int index, float &x, float &y) const
bf1d82
    { mypaint_brush_get_mapping_point(m_brush, id, input, index, &x, &y); }
bf1d82
bf1d82
    float getState(MyPaintBrushState i) const
bf1d82
    { return mypaint_brush_get_state(m_brush, i); }
bf1d82
bf1d82
    void setState(MyPaintBrushState i, float value)
bf1d82
    { return mypaint_brush_set_state(m_brush, i, value); }
bf1d82
bf1d82
    double getTotalStrokePaintingTime() const
bf1d82
    { return mypaint_brush_get_total_stroke_painting_time(m_brush); }
bf1d82
bf1d82
    void setPrintInputs(bool enabled)
bf1d82
    { mypaint_brush_set_print_inputs(m_brush, enabled); }
bf1d82
bf1d82
    void fromDefaults() {
bf1d82
      mypaint_brush_from_defaults(m_brush);
bf1d82
    }
bf1d82
bf1d82
    void fromBrush(const Brush &other) {
bf1d82
      for(int i = 0; i < MYPAINT_BRUSH_SETTINGS_COUNT; ++i) {
bf1d82
        MyPaintBrushSetting id = (MyPaintBrushSetting)i;
bf1d82
        setBaseValue(id, other.getBaseValue(id));
bf1d82
        for(int j = 0; j < MYPAINT_BRUSH_INPUTS_COUNT; ++j) {
bf1d82
          MyPaintBrushInput input = (MyPaintBrushInput)j;
bf1d82
          int n = other.getMappingN(id, input);
bf1d82
          setMappingN(id, input, n);
bf1d82
          for(int index = 0; index < n; ++index) {
bf1d82
            float x = 0.f, y = 0.f;
bf1d82
            other.getMappingPoint(id, input, index, x, y);
bf1d82
            setMappingPoint(id, input, index, x, y);
bf1d82
          }
bf1d82
        }
bf1d82
      }
bf1d82
    }
bf1d82
bf1d82
    bool fromString(const std::string &s) {
bf1d82
      return mypaint_brush_from_string(m_brush, s.c_str());
bf1d82
    }
bf1d82
  };
bf1d82
bf1d82
  //=======================================================
bf1d82
  //
bf1d82
  // Setting
bf1d82
  //
bf1d82
  //=======================================================
bf1d82
bf1d82
  class Setting final {
bf1d82
  public:
bf1d82
    MyPaintBrushSetting id;
bf1d82
    std::string key;
bf1d82
    std::string name;
bf1d82
    std::string tooltip;
bf1d82
    bool constant;
bf1d82
    float min;
bf1d82
    float def;
bf1d82
    float max;
bf1d82
bf1d82
  private:
bf1d82
    Setting():               id(), constant(), min(), def(), max() { }
bf1d82
    Setting(const Setting&): id(), constant(), min(), def(), max() { }
bf1d82
bf1d82
  public:
bf1d82
    static const Setting* all() {
bf1d82
      static bool initialized = false;
bf1d82
      static Setting settings[MYPAINT_BRUSH_SETTINGS_COUNT];
bf1d82
      if (!initialized) {
bf1d82
        for(int i = 0; i < MYPAINT_BRUSH_SETTINGS_COUNT; ++i) {
bf1d82
          const MyPaintBrushSettingInfo *info = mypaint_brush_setting_info((MyPaintBrushSetting)i);
bf1d82
          settings[i].id       = (MyPaintBrushSetting)i;
bf1d82
          settings[i].key      = info->cname;
bf1d82
          settings[i].name     = mypaint_brush_setting_info_get_name(info);
bf1d82
          settings[i].tooltip  = mypaint_brush_setting_info_get_tooltip(info);
bf1d82
          settings[i].constant = info->constant;
bf1d82
          settings[i].min      = info->min;
bf1d82
          settings[i].def      = info->def;
bf1d82
          settings[i].max      = info->max;
bf1d82
        }
bf1d82
      }
bf1d82
      return settings;
bf1d82
    }
bf1d82
bf1d82
    static const Setting& byId(MyPaintBrushSetting id)
bf1d82
      { return all()[id]; }
bf1d82
bf1d82
    static const Setting* findByKey(const std::string &key) {
bf1d82
      const Setting* settings = all();
bf1d82
      for(int i = 0; i < MYPAINT_BRUSH_SETTINGS_COUNT; ++i)
bf1d82
        if (settings[i].key == key)
bf1d82
          return &settings[i];
bf1d82
      return 0;
bf1d82
    }
bf1d82
  };
bf1d82
bf1d82
  //=======================================================
bf1d82
  //
bf1d82
  // Input
bf1d82
  //
bf1d82
  //=======================================================
bf1d82
bf1d82
  class Input final {
bf1d82
  public:
bf1d82
    MyPaintBrushInput id;
bf1d82
    std::string key;
bf1d82
    std::string name;
bf1d82
    std::string tooltip;
bf1d82
    float hardMin;
bf1d82
    float softMin;
bf1d82
    float normal;
bf1d82
    float softMax;
bf1d82
    float hardMax;
bf1d82
bf1d82
  private:
bf1d82
    Input():             id(), hardMin(), softMin(), normal(), softMax(), hardMax() { }
bf1d82
    Input(const Input&): id(), hardMin(), softMin(), normal(), softMax(), hardMax() { }
bf1d82
bf1d82
  public:
bf1d82
    static const Input* all() {
bf1d82
      static bool initialized = false;
bf1d82
      static Input inputs[MYPAINT_BRUSH_INPUTS_COUNT];
bf1d82
      if (!initialized) {
bf1d82
        for(int i = 0; i < MYPAINT_BRUSH_INPUTS_COUNT; ++i) {
bf1d82
          const MyPaintBrushInputInfo *info = mypaint_brush_input_info((MyPaintBrushInput)i);
bf1d82
          inputs[i].id       = (MyPaintBrushInput)i;
bf1d82
          inputs[i].key      = info->cname;
bf1d82
          inputs[i].name     = mypaint_brush_input_info_get_name(info);
bf1d82
          inputs[i].tooltip  = mypaint_brush_input_info_get_tooltip(info);
bf1d82
          inputs[i].hardMin = info->hard_min;
bf1d82
          inputs[i].softMin = info->soft_min;
bf1d82
          inputs[i].normal  = info->normal;
bf1d82
          inputs[i].softMax = info->soft_max;
bf1d82
          inputs[i].hardMax = info->hard_max;
bf1d82
        }
bf1d82
      }
bf1d82
      return inputs;
bf1d82
    }
bf1d82
bf1d82
    static const Input& byId(MyPaintBrushInput id) {
bf1d82
      return all()[id];
bf1d82
    }
bf1d82
bf1d82
    static const Input* findByKey(const std::string &key) {
bf1d82
      const Input* inputs = all();
bf1d82
      for(int i = 0; i < MYPAINT_BRUSH_INPUTS_COUNT; ++i)
bf1d82
        if (inputs[i].key == key)
bf1d82
          return &inputs[i];
bf1d82
      return 0;
bf1d82
    }
bf1d82
  };
bf1d82
}
bf1d82
bf1d82
#endif  // MYPAINT_HPP