<commit_before>#include <algorithm>
#include <utility>

#include "drawtypes/iconset.hpp"
#include "drawtypes/label.hpp"
#include "modules/xworkspaces.hpp"
#include "utils/factory.hpp"
#include "utils/math.hpp"
#include "x11/atoms.hpp"
#include "x11/connection.hpp"

#include "modules/meta/base.inl"

POLYBAR_NS

namespace {
  inline bool operator==(const position& a, const position& b) {
    return a.x + a.y == b.x + b.y;
  }
  inline bool operator!=(const position& a, const position& b) {
    return !(a == b);
  }
}

namespace modules {
  template class module<xworkspaces_module>;

  /**
   * Construct module
   */
  xworkspaces_module::xworkspaces_module(const bar_settings& bar, string name_)
      : static_module<xworkspaces_module>(bar, move(name_)), m_connection(connection::make()) {
    // Load config values
    m_pinworkspaces = m_conf.get(name(), "pin-workspaces", m_pinworkspaces);
    m_click = m_conf.get(name(), "enable-click", m_click);
    m_scroll = m_conf.get(name(), "enable-scroll", m_scroll);

    // Initialize ewmh atoms
    if ((m_ewmh = ewmh_util::initialize()) == nullptr) {
      throw module_error("Failed to initialize ewmh atoms");
    }

    // Check if the WM supports _NET_CURRENT_DESKTOP
    if (!ewmh_util::supports(m_ewmh->_NET_CURRENT_DESKTOP)) {
      throw module_error("The WM does not support _NET_CURRENT_DESKTOP, aborting...");
    }

    // Check if the WM supports _NET_DESKTOP_VIEWPORT
    if (!(m_monitorsupport = ewmh_util::supports(m_ewmh->_NET_DESKTOP_VIEWPORT)) && m_pinworkspaces) {
      throw module_error("The WM does not support _NET_DESKTOP_VIEWPORT (required when `pin-workspaces = true`)");
    }

    // Add formats and elements
    m_formatter->add(DEFAULT_FORMAT, TAG_LABEL_STATE, {TAG_LABEL_STATE, TAG_LABEL_MONITOR});

    if (m_formatter->has(TAG_LABEL_MONITOR)) {
      m_monitorlabel = load_optional_label(m_conf, name(), "label-monitor", DEFAULT_LABEL_MONITOR);
    }

    if (m_formatter->has(TAG_LABEL_STATE)) {
      // clang-format off
      m_labels.insert(make_pair(
          desktop_state::ACTIVE, load_optional_label(m_conf, name(), "label-active", DEFAULT_LABEL_STATE)));
      m_labels.insert(make_pair(
          desktop_state::OCCUPIED, load_optional_label(m_conf, name(), "label-occupied", DEFAULT_LABEL_STATE)));
      m_labels.insert(make_pair(
          desktop_state::URGENT, load_optional_label(m_conf, name(), "label-urgent", DEFAULT_LABEL_STATE)));
      m_labels.insert(make_pair(
          desktop_state::EMPTY, load_optional_label(m_conf, name(), "label-empty", DEFAULT_LABEL_STATE)));
      // clang-format on
    }

    m_icons = factory_util::shared<iconset>();
    m_icons->add(DEFAULT_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_ICON, ""s)));

    for (const auto& workspace : m_conf.get_list<string>(name(), "icon", {})) {
      auto vec = string_util::split(workspace, ';');
      if (vec.size() == 2) {
        m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
      }
    }

    // Get list of monitors
    m_monitors = randr_util::get_monitors(m_connection, m_connection.root(), false);

    // Get desktop details
    m_desktop_names = ewmh_util::get_desktop_names();
    m_current_desktop = ewmh_util::get_current_desktop();

    rebuild_desktops();
    rebuild_desktop_states();

    // Get _NET_CLIENT_LIST
    rebuild_clientlist();
  }

  /**
   * Handler for XCB_PROPERTY_NOTIFY events
   */
  void xworkspaces_module::handle(const evt::property_notify& evt) {
    if (evt->atom == m_ewmh->_NET_CLIENT_LIST) {
      rebuild_clientlist();
    } else if (evt->atom == m_ewmh->_NET_DESKTOP_NAMES) {
      m_desktop_names = ewmh_util::get_desktop_names();
      rebuild_desktops();
      rebuild_desktop_states();
    } else if (evt->atom == m_ewmh->_NET_CURRENT_DESKTOP) {
      m_current_desktop = ewmh_util::get_current_desktop();
      rebuild_desktop_states();
    } else {
      return;
    }

    if (m_timer.allow(evt->time)) {
      broadcast();
    }
  }

  /**
   * Rebuild the list of managed clients
   */
  void xworkspaces_module::rebuild_clientlist() {
    vector<xcb_window_t> clients = ewmh_util::get_client_list();
    vector<xcb_window_t> diff;
    std::sort(clients.begin(), clients.end());
    std::sort(m_clientlist.begin(), m_clientlist.end());

    if (m_clientlist.size() > clients.size()) {
      std::set_difference(
          m_clientlist.begin(), m_clientlist.end(), clients.begin(), clients.end(), back_inserter(diff));
      for (auto&& win : diff) {
        // untrack window
        m_clientlist.erase(std::remove(m_clientlist.begin(), m_clientlist.end(), win), m_clientlist.end());
      }
    } else {
      std::set_difference(
          clients.begin(), clients.end(), m_clientlist.begin(), m_clientlist.end(), back_inserter(diff));
      for (auto&& win : diff) {
        // track window
        m_clientlist.emplace_back(win);
      }
    }
  }

  /**
   * Rebuild the desktop tree
   */
  void xworkspaces_module::rebuild_desktops() {
    m_viewports.clear();

    auto bounds = [&] {
      if (m_monitorsupport) {
        return ewmh_util::get_desktop_viewports();
      } else {
        vector<position> b;
        std::fill_n(std::back_inserter(b), m_desktop_names.size(), position{m_bar.monitor->x, m_bar.monitor->y});
        return b;
      }
    }();

    bounds.erase(std::unique(bounds.begin(), bounds.end(), [](auto& a, auto& b) { return a == b; }), bounds.end());

    unsigned int step = m_desktop_names.size() / bounds.size();
    unsigned int offset = 0;
    for (unsigned int i = 0; i < bounds.size(); i++) {
      if (!m_pinworkspaces || m_bar.monitor->match(bounds[i])) {
        auto viewport = make_unique<struct viewport>();
        viewport->state = viewport_state::UNFOCUSED;
        viewport->pos = bounds[i];

        for (auto&& m : m_monitors) {
          if (m->match(viewport->pos)) {
            viewport->name = m->name;
            viewport->state = viewport_state::FOCUSED;
          }
        }

        viewport->label = [&] {
          label_t label;
          if (m_monitorlabel) {
            label = m_monitorlabel->clone();
            label->reset_tokens();
            label->replace_token("%name%", viewport->name);
          }
          return label;
        }();

        for (unsigned int index = offset; index < offset + step; index++) {
          viewport->desktops.emplace_back(make_unique<struct desktop>(index, offset, desktop_state::EMPTY, label_t{}));
        }

        m_viewports.emplace_back(move(viewport));
      }
      offset += step;
    }
  }

  /**
   * Update active state of current desktops
   */
  void xworkspaces_module::rebuild_desktop_states() {
    for (auto&& v : m_viewports) {
      for (auto&& d : v->desktops) {
        if (d->index == m_current_desktop && d->state != desktop_state::ACTIVE) {
          d->state = desktop_state::ACTIVE;
        } else if (d->state == desktop_state::ACTIVE) {
          d->state = desktop_state::EMPTY;
        } else if (d->label) {
          continue;
        }

        d->label = m_labels.at(d->state)->clone();
        d->label->reset_tokens();
        d->label->replace_token("%index%", to_string(d->index - d->offset + 1));
        d->label->replace_token("%name%", m_desktop_names[d->index]);
        d->label->replace_token("%icon%", m_icons->get(m_desktop_names[d->index], DEFAULT_ICON)->get());
      }
    }
  }

  /**
   * Fetch and parse data
   */
  void xworkspaces_module::update() {}

  /**
   * Generate module output
   */
  string xworkspaces_module::get_output() {
    // Get the module output early so that
    // the format prefix/suffix also gets wrapped
    // with the cmd handlers
    string output;
    for (m_index = 0; m_index < m_viewports.size(); m_index++) {
      if (m_index > 0) {
        m_builder->space(m_formatter->get(DEFAULT_FORMAT)->spacing);
      }
      output += module::get_output();
    }

    m_builder->cmd(mousebtn::SCROLL_DOWN, string{EVENT_PREFIX} + string{EVENT_SCROLL_DOWN});
    m_builder->cmd(mousebtn::SCROLL_UP, string{EVENT_PREFIX} + string{EVENT_SCROLL_UP});

    m_builder->append(output);

    m_builder->cmd_close();
    m_builder->cmd_close();

    return m_builder->flush();
  }

  /**
   * Output content as defined in the config
   */
  bool xworkspaces_module::build(builder* builder, const string& tag) const {
    if (tag == TAG_LABEL_MONITOR) {
      if (m_viewports[m_index]->state != viewport_state::NONE) {
        builder->node(m_viewports[m_index]->label);
        return true;
      } else {
        return false;
      }
    } else if (tag == TAG_LABEL_STATE) {
      unsigned int added_states = 0;
      for (auto&& desktop : m_viewports[m_index]->desktops) {
        if (desktop->label.get()) {
          if (m_click && desktop->state != desktop_state::ACTIVE) {
            builder->cmd(mousebtn::LEFT, string{EVENT_PREFIX} + string{EVENT_CLICK} + to_string(desktop->index));
            builder->node(desktop->label);
            builder->cmd_close();
          } else {
            builder->node(desktop->label);
          }
          added_states++;
        }
      }
      return added_states > 0;
    } else {
      return false;
    }
  }

  /**
   * Handle user input event
   */
  bool xworkspaces_module::input(string&& cmd) {
    size_t len{strlen(EVENT_PREFIX)};
    if (cmd.compare(0, len, EVENT_PREFIX) != 0) {
      return false;
    }
    cmd.erase(0, len);

    vector<unsigned int> indexes;
    for (auto&& viewport : m_viewports) {
      for (auto&& desktop : viewport->desktops) {
        indexes.emplace_back(desktop->index);
      }
    }

    std::sort(indexes.begin(), indexes.end());

    unsigned int new_desktop{0};
    unsigned int current_desktop{ewmh_util::get_current_desktop()};

    if ((len = strlen(EVENT_CLICK)) && cmd.compare(0, len, EVENT_CLICK) == 0) {
      new_desktop = std::strtoul(cmd.substr(len).c_str(), nullptr, 10);
    } else if ((len = strlen(EVENT_SCROLL_UP)) && cmd.compare(0, len, EVENT_SCROLL_UP) == 0) {
      new_desktop = math_util::min<unsigned int>(indexes.back(), current_desktop + 1);
      new_desktop = new_desktop == current_desktop ? indexes.front() : new_desktop;
    } else if ((len = strlen(EVENT_SCROLL_DOWN)) && cmd.compare(0, len, EVENT_SCROLL_DOWN) == 0) {
      new_desktop = math_util::max<unsigned int>(indexes.front(), current_desktop - 1);
      new_desktop = new_desktop == current_desktop ? indexes.back() : new_desktop;
    }

    if (new_desktop != current_desktop) {
      m_log.info("%s: Requesting change to desktop #%u", name(), new_desktop);
      ewmh_util::change_current_desktop(new_desktop);
    } else {
      m_log.info("%s: Ignoring change to current desktop", name());
    }

    return true;
  }
}

POLYBAR_NS_END
<commit_msg>fix(ci): Remove unused function<commit_after>#include <algorithm>
#include <utility>

#include "drawtypes/iconset.hpp"
#include "drawtypes/label.hpp"
#include "modules/xworkspaces.hpp"
#include "utils/factory.hpp"
#include "utils/math.hpp"
#include "x11/atoms.hpp"
#include "x11/connection.hpp"

#include "modules/meta/base.inl"

POLYBAR_NS

namespace {
  inline bool operator==(const position& a, const position& b) {
    return a.x + a.y == b.x + b.y;
  }
}

namespace modules {
  template class module<xworkspaces_module>;

  /**
   * Construct module
   */
  xworkspaces_module::xworkspaces_module(const bar_settings& bar, string name_)
      : static_module<xworkspaces_module>(bar, move(name_)), m_connection(connection::make()) {
    // Load config values
    m_pinworkspaces = m_conf.get(name(), "pin-workspaces", m_pinworkspaces);
    m_click = m_conf.get(name(), "enable-click", m_click);
    m_scroll = m_conf.get(name(), "enable-scroll", m_scroll);

    // Initialize ewmh atoms
    if ((m_ewmh = ewmh_util::initialize()) == nullptr) {
      throw module_error("Failed to initialize ewmh atoms");
    }

    // Check if the WM supports _NET_CURRENT_DESKTOP
    if (!ewmh_util::supports(m_ewmh->_NET_CURRENT_DESKTOP)) {
      throw module_error("The WM does not support _NET_CURRENT_DESKTOP, aborting...");
    }

    // Check if the WM supports _NET_DESKTOP_VIEWPORT
    if (!(m_monitorsupport = ewmh_util::supports(m_ewmh->_NET_DESKTOP_VIEWPORT)) && m_pinworkspaces) {
      throw module_error("The WM does not support _NET_DESKTOP_VIEWPORT (required when `pin-workspaces = true`)");
    }

    // Add formats and elements
    m_formatter->add(DEFAULT_FORMAT, TAG_LABEL_STATE, {TAG_LABEL_STATE, TAG_LABEL_MONITOR});

    if (m_formatter->has(TAG_LABEL_MONITOR)) {
      m_monitorlabel = load_optional_label(m_conf, name(), "label-monitor", DEFAULT_LABEL_MONITOR);
    }

    if (m_formatter->has(TAG_LABEL_STATE)) {
      // clang-format off
      m_labels.insert(make_pair(
          desktop_state::ACTIVE, load_optional_label(m_conf, name(), "label-active", DEFAULT_LABEL_STATE)));
      m_labels.insert(make_pair(
          desktop_state::OCCUPIED, load_optional_label(m_conf, name(), "label-occupied", DEFAULT_LABEL_STATE)));
      m_labels.insert(make_pair(
          desktop_state::URGENT, load_optional_label(m_conf, name(), "label-urgent", DEFAULT_LABEL_STATE)));
      m_labels.insert(make_pair(
          desktop_state::EMPTY, load_optional_label(m_conf, name(), "label-empty", DEFAULT_LABEL_STATE)));
      // clang-format on
    }

    m_icons = factory_util::shared<iconset>();
    m_icons->add(DEFAULT_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_ICON, ""s)));

    for (const auto& workspace : m_conf.get_list<string>(name(), "icon", {})) {
      auto vec = string_util::split(workspace, ';');
      if (vec.size() == 2) {
        m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
      }
    }

    // Get list of monitors
    m_monitors = randr_util::get_monitors(m_connection, m_connection.root(), false);

    // Get desktop details
    m_desktop_names = ewmh_util::get_desktop_names();
    m_current_desktop = ewmh_util::get_current_desktop();

    rebuild_desktops();
    rebuild_desktop_states();

    // Get _NET_CLIENT_LIST
    rebuild_clientlist();
  }

  /**
   * Handler for XCB_PROPERTY_NOTIFY events
   */
  void xworkspaces_module::handle(const evt::property_notify& evt) {
    if (evt->atom == m_ewmh->_NET_CLIENT_LIST) {
      rebuild_clientlist();
    } else if (evt->atom == m_ewmh->_NET_DESKTOP_NAMES) {
      m_desktop_names = ewmh_util::get_desktop_names();
      rebuild_desktops();
      rebuild_desktop_states();
    } else if (evt->atom == m_ewmh->_NET_CURRENT_DESKTOP) {
      m_current_desktop = ewmh_util::get_current_desktop();
      rebuild_desktop_states();
    } else {
      return;
    }

    if (m_timer.allow(evt->time)) {
      broadcast();
    }
  }

  /**
   * Rebuild the list of managed clients
   */
  void xworkspaces_module::rebuild_clientlist() {
    vector<xcb_window_t> clients = ewmh_util::get_client_list();
    vector<xcb_window_t> diff;
    std::sort(clients.begin(), clients.end());
    std::sort(m_clientlist.begin(), m_clientlist.end());

    if (m_clientlist.size() > clients.size()) {
      std::set_difference(
          m_clientlist.begin(), m_clientlist.end(), clients.begin(), clients.end(), back_inserter(diff));
      for (auto&& win : diff) {
        // untrack window
        m_clientlist.erase(std::remove(m_clientlist.begin(), m_clientlist.end(), win), m_clientlist.end());
      }
    } else {
      std::set_difference(
          clients.begin(), clients.end(), m_clientlist.begin(), m_clientlist.end(), back_inserter(diff));
      for (auto&& win : diff) {
        // track window
        m_clientlist.emplace_back(win);
      }
    }
  }

  /**
   * Rebuild the desktop tree
   */
  void xworkspaces_module::rebuild_desktops() {
    m_viewports.clear();

    auto bounds = [&] {
      if (m_monitorsupport) {
        return ewmh_util::get_desktop_viewports();
      } else {
        vector<position> b;
        std::fill_n(std::back_inserter(b), m_desktop_names.size(), position{m_bar.monitor->x, m_bar.monitor->y});
        return b;
      }
    }();

    bounds.erase(std::unique(bounds.begin(), bounds.end(), [](auto& a, auto& b) { return a == b; }), bounds.end());

    unsigned int step = m_desktop_names.size() / bounds.size();
    unsigned int offset = 0;
    for (unsigned int i = 0; i < bounds.size(); i++) {
      if (!m_pinworkspaces || m_bar.monitor->match(bounds[i])) {
        auto viewport = make_unique<struct viewport>();
        viewport->state = viewport_state::UNFOCUSED;
        viewport->pos = bounds[i];

        for (auto&& m : m_monitors) {
          if (m->match(viewport->pos)) {
            viewport->name = m->name;
            viewport->state = viewport_state::FOCUSED;
          }
        }

        viewport->label = [&] {
          label_t label;
          if (m_monitorlabel) {
            label = m_monitorlabel->clone();
            label->reset_tokens();
            label->replace_token("%name%", viewport->name);
          }
          return label;
        }();

        for (unsigned int index = offset; index < offset + step; index++) {
          viewport->desktops.emplace_back(make_unique<struct desktop>(index, offset, desktop_state::EMPTY, label_t{}));
        }

        m_viewports.emplace_back(move(viewport));
      }
      offset += step;
    }
  }

  /**
   * Update active state of current desktops
   */
  void xworkspaces_module::rebuild_desktop_states() {
    for (auto&& v : m_viewports) {
      for (auto&& d : v->desktops) {
        if (d->index == m_current_desktop && d->state != desktop_state::ACTIVE) {
          d->state = desktop_state::ACTIVE;
        } else if (d->state == desktop_state::ACTIVE) {
          d->state = desktop_state::EMPTY;
        } else if (d->label) {
          continue;
        }

        d->label = m_labels.at(d->state)->clone();
        d->label->reset_tokens();
        d->label->replace_token("%index%", to_string(d->index - d->offset + 1));
        d->label->replace_token("%name%", m_desktop_names[d->index]);
        d->label->replace_token("%icon%", m_icons->get(m_desktop_names[d->index], DEFAULT_ICON)->get());
      }
    }
  }

  /**
   * Fetch and parse data
   */
  void xworkspaces_module::update() {}

  /**
   * Generate module output
   */
  string xworkspaces_module::get_output() {
    // Get the module output early so that
    // the format prefix/suffix also gets wrapped
    // with the cmd handlers
    string output;
    for (m_index = 0; m_index < m_viewports.size(); m_index++) {
      if (m_index > 0) {
        m_builder->space(m_formatter->get(DEFAULT_FORMAT)->spacing);
      }
      output += module::get_output();
    }

    m_builder->cmd(mousebtn::SCROLL_DOWN, string{EVENT_PREFIX} + string{EVENT_SCROLL_DOWN});
    m_builder->cmd(mousebtn::SCROLL_UP, string{EVENT_PREFIX} + string{EVENT_SCROLL_UP});

    m_builder->append(output);

    m_builder->cmd_close();
    m_builder->cmd_close();

    return m_builder->flush();
  }

  /**
   * Output content as defined in the config
   */
  bool xworkspaces_module::build(builder* builder, const string& tag) const {
    if (tag == TAG_LABEL_MONITOR) {
      if (m_viewports[m_index]->state != viewport_state::NONE) {
        builder->node(m_viewports[m_index]->label);
        return true;
      } else {
        return false;
      }
    } else if (tag == TAG_LABEL_STATE) {
      unsigned int added_states = 0;
      for (auto&& desktop : m_viewports[m_index]->desktops) {
        if (desktop->label.get()) {
          if (m_click && desktop->state != desktop_state::ACTIVE) {
            builder->cmd(mousebtn::LEFT, string{EVENT_PREFIX} + string{EVENT_CLICK} + to_string(desktop->index));
            builder->node(desktop->label);
            builder->cmd_close();
          } else {
            builder->node(desktop->label);
          }
          added_states++;
        }
      }
      return added_states > 0;
    } else {
      return false;
    }
  }

  /**
   * Handle user input event
   */
  bool xworkspaces_module::input(string&& cmd) {
    size_t len{strlen(EVENT_PREFIX)};
    if (cmd.compare(0, len, EVENT_PREFIX) != 0) {
      return false;
    }
    cmd.erase(0, len);

    vector<unsigned int> indexes;
    for (auto&& viewport : m_viewports) {
      for (auto&& desktop : viewport->desktops) {
        indexes.emplace_back(desktop->index);
      }
    }

    std::sort(indexes.begin(), indexes.end());

    unsigned int new_desktop{0};
    unsigned int current_desktop{ewmh_util::get_current_desktop()};

    if ((len = strlen(EVENT_CLICK)) && cmd.compare(0, len, EVENT_CLICK) == 0) {
      new_desktop = std::strtoul(cmd.substr(len).c_str(), nullptr, 10);
    } else if ((len = strlen(EVENT_SCROLL_UP)) && cmd.compare(0, len, EVENT_SCROLL_UP) == 0) {
      new_desktop = math_util::min<unsigned int>(indexes.back(), current_desktop + 1);
      new_desktop = new_desktop == current_desktop ? indexes.front() : new_desktop;
    } else if ((len = strlen(EVENT_SCROLL_DOWN)) && cmd.compare(0, len, EVENT_SCROLL_DOWN) == 0) {
      new_desktop = math_util::max<unsigned int>(indexes.front(), current_desktop - 1);
      new_desktop = new_desktop == current_desktop ? indexes.back() : new_desktop;
    }

    if (new_desktop != current_desktop) {
      m_log.info("%s: Requesting change to desktop #%u", name(), new_desktop);
      ewmh_util::change_current_desktop(new_desktop);
    } else {
      m_log.info("%s: Ignoring change to current desktop", name());
    }

    return true;
  }
}

POLYBAR_NS_END
<|endoftext|>


<commit_before>#include <algorithm>

#include <utki/debug.hpp>

#include "../util/RasterImage.hpp"
#include "../util/util.hpp"

#include "TexFont.hxx"
#include "../context.hpp"

//TODO: remove
#include "../gui.hpp"

using namespace morda;

namespace{

constexpr const char32_t unknownChar_c = 0xfffd;

}

TexFont::FreeTypeLibWrapper::FreeTypeLibWrapper() {
	if (FT_Init_FreeType(&this->lib)) {
		throw utki::Exc("FreeTypeLibWrapper::FreeTypeLibWrapper(): unable to init freetype library");
	}
}

TexFont::FreeTypeLibWrapper::~FreeTypeLibWrapper()noexcept{
	FT_Done_FreeType(this->lib);
}

TexFont::FreeTypeFaceWrapper::FreeTypeFaceWrapper(FT_Library& lib, const papki::File& fi) {
	this->fontFile = fi.loadWholeFileIntoMemory();
	if (FT_New_Memory_Face(lib, & * this->fontFile.begin(), int(this->fontFile.size()), 0/* face_index */, &this->f) != 0) {
		throw utki::Exc("FreeTypeFaceWrapper::FreeTypeFaceWrapper(): unable to crate font face object");
	}
}

TexFont::FreeTypeFaceWrapper::~FreeTypeFaceWrapper()noexcept{
	FT_Done_Face(this->f);
}
TexFont::Glyph TexFont::loadGlyph(char32_t c) const{
	if(FT_Load_Char(this->face.f, FT_ULong(c), FT_LOAD_RENDER) != 0){
		if(c == unknownChar_c){
			throw std::runtime_error("TexFont::loadGlyph(): could not load 'unknown character' glyph (UTF-32: 0xfffd)");
		}
		TRACE(<< "TexFont::loadGlyph(" << std::hex << std::uint32_t(c) << "): failed to load glyph" << std::endl)
		return this->unknownGlyph;
	}

	FT_GlyphSlot slot = this->face.f->glyph;

	FT_Glyph_Metrics *m = &slot->metrics;

	Glyph g;
	g.advance = real(m->horiAdvance) / (64.0f);

	if(!slot->bitmap.buffer){
		//empty glyph (space, tab, etc...)

		return g;
	}

	RasterImage glyphim(r4::vec2ui(slot->bitmap.width, slot->bitmap.rows), RasterImage::ColorDepth_e::GREY, slot->bitmap.buffer);

	RasterImage im(glyphim.dim(), RasterImage::ColorDepth_e::GREYA);
	im.blit(0, 0, glyphim, 1, 0);
	im.clear(0, std::uint8_t(0xff));

	std::array<r4::vec2f, 4> verts;
	verts[0] = (morda::Vec2r(real(m->horiBearingX), -real(m->horiBearingY)) / (64.0f));
	verts[1] = (morda::Vec2r(real(m->horiBearingX), real(m->height - m->horiBearingY)) / (64.0f));
	verts[2] = (morda::Vec2r(real(m->horiBearingX + m->width), real(m->height - m->horiBearingY)) / (64.0f));
	verts[3] = (morda::Vec2r(real(m->horiBearingX + m->width), -real(m->horiBearingY)) / (64.0f));

	g.topLeft = verts[0];
	g.bottomRight = verts[2];

	auto& r = *this->context->renderer;
	g.vao = r.factory->create_vertex_array(
			{
				r.factory->create_vertex_buffer(utki::make_span(verts)),
				this->context->renderer->quad_01_vbo
			},
			this->context->renderer->quad_indices,
			vertex_array::mode::triangle_fan
		);
	g.tex = this->context->renderer->factory->create_texture_2d(
			morda::numChannelsToTexType(im.numChannels()),
			im.dim(),
			im.buf()
		);

	return g;
}

TexFont::TexFont(std::shared_ptr<morda::context> c, const papki::file& fi, unsigned fontSize, unsigned maxCached) :
		Font(std::move(c)),
		maxCached(maxCached),
		face(freetype.lib, fi)
{
//	TRACE(<< "TexFont::Load(): enter" << std::endl)

	// set character size in pixels
	{
		FT_Error error = FT_Set_Pixel_Sizes(
				this->face.f,
				0, // pixel_width (0 means "same as height")
				fontSize // pixel_height
			);

		if(error != 0){
			throw utki::Exc("TexFont::TexFont(): unable to set char size");
		}
	}

	this->unknownGlyph = this->loadGlyph(unknownChar_c);

//	TRACE(<< "TexFont::Load(): entering for loop" << std::endl)

	using std::ceil;

	this->height_v = ceil((this->face.f->size->metrics.height) / 64.0f);
	this->descender_v = -ceil((this->face.f->size->metrics.descender) / 64.0f);
	this->ascender_v = ceil((this->face.f->size->metrics.ascender) / 64.0f);

//	TRACE(<< "TexFont::TexFont(): height_v = " << this->height_v << std::endl)
}

const TexFont::Glyph& TexFont::getGlyph(char32_t c)const{
	auto i = this->glyphs.find(c);
	if(i == this->glyphs.end()){
		auto r = this->glyphs.insert(std::make_pair(c, this->loadGlyph(c)));
		ASSERT(r.second)
		i = r.first;
		this->lastUsedOrder.push_front(c);
		i->second.lastUsedIter = this->lastUsedOrder.begin();

		if(this->lastUsedOrder.size() == this->maxCached){
			this->glyphs.erase(this->lastUsedOrder.back());
			this->lastUsedOrder.pop_back();
		}
//		TRACE(<< "TexFont::getGlyph(): glyph loaded: " << c << std::endl)
	}else{
		Glyph& g = i->second;
		this->lastUsedOrder.splice(this->lastUsedOrder.begin(), this->lastUsedOrder, g.lastUsedIter);
	}

	ASSERT(this->lastUsedOrder.size() <= this->maxCached)

	return i->second;
}

real TexFont::renderGlyphInternal(const morda::Matr4r& matrix, r4::vec4f color, char32_t ch)const{
	const Glyph& g = this->getGlyph(ch);

	// texture can be null for glyph of empty characters, like space, tab etc...
	if(g.tex){
		ASSERT(g.vao)
		this->context->renderer->shader->color_pos_tex->render(matrix, *g.vao, color, *g.tex);
	}

	return g.advance;
}

real TexFont::stringAdvanceInternal(const std::u32string& str)const{
	real ret = 0;

	auto s = str.begin();

	for(; s != str.end(); ++s){
		try{
			const Glyph& g = this->getGlyph(*s);
			ret += g.advance;
		}catch(std::out_of_range&){
			// ignore
		}
	}

	return ret;
}

morda::Rectr TexFont::stringBoundingBoxInternal(const std::u32string& str)const{
	morda::Rectr ret;

	if(str.size() == 0){
		ret.p.set(0);
		ret.d.set(0);
		return ret;
	}

	auto s = str.begin();

	real curAdvance;

	real left, right, top, bottom;
	//init with bounding box of the first glyph
	{
		const Glyph& g = this->getGlyph(*s);
		left = g.topLeft.x;
		right = g.bottomRight.x;
		top = g.topLeft.y;
		bottom = g.bottomRight.y;
		curAdvance = g.advance;
		++s;
	}

	for(; s != str.end(); ++s){
		const Glyph& g = this->getGlyph(*s);

		using std::min;
		using std::max;

		top = min(g.topLeft.y, top);
		bottom = max(g.bottomRight.y, bottom);
		left = min(curAdvance + g.topLeft.x, left);
		right = max(curAdvance + g.bottomRight.x, right);

		curAdvance += g.advance;
	}

	ret.p.x = left;
	ret.p.y = top;
	ret.d.x = right - left;
	ret.d.y = -(top - bottom);

	ASSERT(ret.d.x >= 0)
	ASSERT(ret.d.y >= 0)
//	TRACE(<< "TexFont::stringBoundingBoxInternal(): ret = " << ret << std::endl)
	return ret;
}

real TexFont::renderStringInternal(const morda::Matr4r& matrix, r4::vec4f color, const std::u32string& str)const{
	if(str.size() == 0){
		return 0;
	}

	applySimpleAlphaBlending(*this->context->renderer);

	real ret = 0;

	morda::Matr4r matr(matrix);

	auto s = str.begin();

	for(; s != str.end(); ++s){
		try{
			real advance = this->renderGlyphInternal(matr, color, *s);
			ret += advance;
			matr.translate(advance, 0);
		}catch(std::out_of_range&){
			//ignore
		}
	}

	return ret;
}

real TexFont::charAdvance(char32_t c) const{
	auto& g = this->getGlyph(c);
	return g.advance;
}
<commit_msg>stuff<commit_after>#include <algorithm>

#include <utki/debug.hpp>

#include "../util/RasterImage.hpp"
#include "../util/util.hpp"

#include "TexFont.hxx"
#include "../context.hpp"

using namespace morda;

namespace{
constexpr const char32_t unknownChar_c = 0xfffd;
}

TexFont::FreeTypeLibWrapper::FreeTypeLibWrapper() {
	if (FT_Init_FreeType(&this->lib)) {
		throw utki::Exc("FreeTypeLibWrapper::FreeTypeLibWrapper(): unable to init freetype library");
	}
}

TexFont::FreeTypeLibWrapper::~FreeTypeLibWrapper()noexcept{
	FT_Done_FreeType(this->lib);
}

TexFont::FreeTypeFaceWrapper::FreeTypeFaceWrapper(FT_Library& lib, const papki::File& fi) {
	this->fontFile = fi.loadWholeFileIntoMemory();
	if (FT_New_Memory_Face(lib, & * this->fontFile.begin(), int(this->fontFile.size()), 0/* face_index */, &this->f) != 0) {
		throw utki::Exc("FreeTypeFaceWrapper::FreeTypeFaceWrapper(): unable to crate font face object");
	}
}

TexFont::FreeTypeFaceWrapper::~FreeTypeFaceWrapper()noexcept{
	FT_Done_Face(this->f);
}
TexFont::Glyph TexFont::loadGlyph(char32_t c) const{
	if(FT_Load_Char(this->face.f, FT_ULong(c), FT_LOAD_RENDER) != 0){
		if(c == unknownChar_c){
			throw std::runtime_error("TexFont::loadGlyph(): could not load 'unknown character' glyph (UTF-32: 0xfffd)");
		}
		TRACE(<< "TexFont::loadGlyph(" << std::hex << std::uint32_t(c) << "): failed to load glyph" << std::endl)
		return this->unknownGlyph;
	}

	FT_GlyphSlot slot = this->face.f->glyph;

	FT_Glyph_Metrics *m = &slot->metrics;

	Glyph g;
	g.advance = real(m->horiAdvance) / (64.0f);

	if(!slot->bitmap.buffer){
		//empty glyph (space, tab, etc...)

		return g;
	}

	RasterImage glyphim(r4::vec2ui(slot->bitmap.width, slot->bitmap.rows), RasterImage::ColorDepth_e::GREY, slot->bitmap.buffer);

	RasterImage im(glyphim.dim(), RasterImage::ColorDepth_e::GREYA);
	im.blit(0, 0, glyphim, 1, 0);
	im.clear(0, std::uint8_t(0xff));

	std::array<r4::vec2f, 4> verts;
	verts[0] = (morda::Vec2r(real(m->horiBearingX), -real(m->horiBearingY)) / (64.0f));
	verts[1] = (morda::Vec2r(real(m->horiBearingX), real(m->height - m->horiBearingY)) / (64.0f));
	verts[2] = (morda::Vec2r(real(m->horiBearingX + m->width), real(m->height - m->horiBearingY)) / (64.0f));
	verts[3] = (morda::Vec2r(real(m->horiBearingX + m->width), -real(m->horiBearingY)) / (64.0f));

	g.topLeft = verts[0];
	g.bottomRight = verts[2];

	auto& r = *this->context->renderer;
	g.vao = r.factory->create_vertex_array(
			{
				r.factory->create_vertex_buffer(utki::make_span(verts)),
				this->context->renderer->quad_01_vbo
			},
			this->context->renderer->quad_indices,
			vertex_array::mode::triangle_fan
		);
	g.tex = this->context->renderer->factory->create_texture_2d(
			morda::numChannelsToTexType(im.numChannels()),
			im.dim(),
			im.buf()
		);

	return g;
}

TexFont::TexFont(std::shared_ptr<morda::context> c, const papki::file& fi, unsigned fontSize, unsigned maxCached) :
		Font(std::move(c)),
		maxCached(maxCached),
		face(freetype.lib, fi)
{
//	TRACE(<< "TexFont::Load(): enter" << std::endl)

	// set character size in pixels
	{
		FT_Error error = FT_Set_Pixel_Sizes(
				this->face.f,
				0, // pixel_width (0 means "same as height")
				fontSize // pixel_height
			);

		if(error != 0){
			throw utki::Exc("TexFont::TexFont(): unable to set char size");
		}
	}

	this->unknownGlyph = this->loadGlyph(unknownChar_c);

//	TRACE(<< "TexFont::Load(): entering for loop" << std::endl)

	using std::ceil;

	this->height_v = ceil((this->face.f->size->metrics.height) / 64.0f);
	this->descender_v = -ceil((this->face.f->size->metrics.descender) / 64.0f);
	this->ascender_v = ceil((this->face.f->size->metrics.ascender) / 64.0f);

//	TRACE(<< "TexFont::TexFont(): height_v = " << this->height_v << std::endl)
}

const TexFont::Glyph& TexFont::getGlyph(char32_t c)const{
	auto i = this->glyphs.find(c);
	if(i == this->glyphs.end()){
		auto r = this->glyphs.insert(std::make_pair(c, this->loadGlyph(c)));
		ASSERT(r.second)
		i = r.first;
		this->lastUsedOrder.push_front(c);
		i->second.lastUsedIter = this->lastUsedOrder.begin();

		if(this->lastUsedOrder.size() == this->maxCached){
			this->glyphs.erase(this->lastUsedOrder.back());
			this->lastUsedOrder.pop_back();
		}
//		TRACE(<< "TexFont::getGlyph(): glyph loaded: " << c << std::endl)
	}else{
		Glyph& g = i->second;
		this->lastUsedOrder.splice(this->lastUsedOrder.begin(), this->lastUsedOrder, g.lastUsedIter);
	}

	ASSERT(this->lastUsedOrder.size() <= this->maxCached)

	return i->second;
}

real TexFont::renderGlyphInternal(const morda::Matr4r& matrix, r4::vec4f color, char32_t ch)const{
	const Glyph& g = this->getGlyph(ch);

	// texture can be null for glyph of empty characters, like space, tab etc...
	if(g.tex){
		ASSERT(g.vao)
		this->context->renderer->shader->color_pos_tex->render(matrix, *g.vao, color, *g.tex);
	}

	return g.advance;
}

real TexFont::stringAdvanceInternal(const std::u32string& str)const{
	real ret = 0;

	auto s = str.begin();

	for(; s != str.end(); ++s){
		try{
			const Glyph& g = this->getGlyph(*s);
			ret += g.advance;
		}catch(std::out_of_range&){
			// ignore
		}
	}

	return ret;
}

morda::Rectr TexFont::stringBoundingBoxInternal(const std::u32string& str)const{
	morda::Rectr ret;

	if(str.size() == 0){
		ret.p.set(0);
		ret.d.set(0);
		return ret;
	}

	auto s = str.begin();

	real curAdvance;

	real left, right, top, bottom;
	//init with bounding box of the first glyph
	{
		const Glyph& g = this->getGlyph(*s);
		left = g.topLeft.x;
		right = g.bottomRight.x;
		top = g.topLeft.y;
		bottom = g.bottomRight.y;
		curAdvance = g.advance;
		++s;
	}

	for(; s != str.end(); ++s){
		const Glyph& g = this->getGlyph(*s);

		using std::min;
		using std::max;

		top = min(g.topLeft.y, top);
		bottom = max(g.bottomRight.y, bottom);
		left = min(curAdvance + g.topLeft.x, left);
		right = max(curAdvance + g.bottomRight.x, right);

		curAdvance += g.advance;
	}

	ret.p.x = left;
	ret.p.y = top;
	ret.d.x = right - left;
	ret.d.y = -(top - bottom);

	ASSERT(ret.d.x >= 0)
	ASSERT(ret.d.y >= 0)
//	TRACE(<< "TexFont::stringBoundingBoxInternal(): ret = " << ret << std::endl)
	return ret;
}

real TexFont::renderStringInternal(const morda::Matr4r& matrix, r4::vec4f color, const std::u32string& str)const{
	if(str.size() == 0){
		return 0;
	}

	applySimpleAlphaBlending(*this->context->renderer);

	real ret = 0;

	morda::Matr4r matr(matrix);

	auto s = str.begin();

	for(; s != str.end(); ++s){
		try{
			real advance = this->renderGlyphInternal(matr, color, *s);
			ret += advance;
			matr.translate(advance, 0);
		}catch(std::out_of_range&){
			//ignore
		}
	}

	return ret;
}

real TexFont::charAdvance(char32_t c) const{
	auto& g = this->getGlyph(c);
	return g.advance;
}
<|endoftext|>


<commit_before>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish_poremodel -- Representation of the Oxford
// Nanopore sequencing model, as described in a FAST5 file
//
#ifndef __POREMODEL_HPP
#define __POREMODEL_HPP

#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>

#include "Kmer.hpp"
#include "Event.hpp"
#include "fast5.hpp"
#include "alg.hpp"

template < typename Float_Type >
inline Float_Type log_normal_pdf(Float_Type x, Float_Type mean, Float_Type stdv, Float_Type log_stdv)
{
    // From SO: http://stackoverflow.com/questions/10847007/using-the-gaussian-probability-density-function-in-c
    static const Float_Type log_2pi = std::log(2.0 * M_PI);
    Float_Type a = (x - mean) / stdv;
    return - log_stdv - (log_2pi + a * a) / static_cast< Float_Type >(2.0);
}

template < typename Float_Type >
inline Float_Type log_invgauss_pdf(Float_Type x, Float_Type log_x,
                                   Float_Type mu, Float_Type lambda, Float_Type log_lambda)
{
    static const Float_Type log_2pi = std::log(2.0 * M_PI);
    Float_Type a = (x - mu) / mu;
    return (log_lambda - log_2pi - static_cast< Float_Type >(3.0) * log_x - lambda * a * a / x) / static_cast< Float_Type >(2.0);
}

template < typename Float_Type >
struct Pore_Model_Parameters
{
    Pore_Model_Parameters() : scale(1.0), shift(0.0), drift(0.0), var(1.0), scale_sd(1.0), var_sd(1.0) {}

    Float_Type scale;
    Float_Type shift;
    Float_Type drift;
    Float_Type var;
    Float_Type scale_sd;
    Float_Type var_sd;

    void load_from_fast5(const fast5::File& f, bool strand)
    {
        assert(f.have_basecall_model(strand));
        auto m_p = f.get_basecall_model_params(strand);
        scale = m_p.scale;
        shift = m_p.shift;
        drift = m_p.drift;
        var = m_p.var;
        scale_sd = m_p.scale_sd;
        var_sd = m_p.var_sd;
    }

    friend std::ostream& operator << (std::ostream& os, const Pore_Model_Parameters& p)
    {
        os << "[scale=" << p.scale << " shift=" << p.shift << " drift=" << p.drift
           << " var=" << p.var << " scale_sd=" << p.scale_sd << " var_sd=" << p.var_sd << "]";
        return os;
    }
    void write_tsv(std::ostream& os) const
    {
        os << std::fixed << std::setprecision(5)
           << scale << '\t' << shift << '\t' << drift << '\t' << var << '\t' << scale_sd << '\t' << var_sd;
    }
}; // struct Pore_Model_Parameters

template < typename Float_Type, unsigned Kmer_Size >
struct Pore_Model_State
{
    typedef Event< Float_Type, Kmer_Size > Event_Type;
    typedef Pore_Model_Parameters< Float_Type > Pore_Model_Parameters_Type;

    Float_Type level_mean;
    Float_Type level_stdv;
    Float_Type sd_mean;
    Float_Type sd_stdv;
    Float_Type sd_lambda;

    Float_Type log_level_mean;
    Float_Type log_level_stdv;
    Float_Type log_sd_mean;
    Float_Type log_sd_stdv;
    Float_Type log_sd_lambda;

    std::array< char, Kmer_Size > kmer;

    Pore_Model_State& operator = (const fast5::Model_Entry& e)
    {
        level_mean = e.level_mean;
        level_stdv = e.level_stdv;
        sd_mean = e.sd_mean;
        sd_stdv = e.sd_stdv;
        std::copy_n(e.kmer.begin(), Kmer_Size, kmer.begin());
        update_sd_lambda();
        update_logs();
        return *this;
    }

    // update sd_lambda based on sd_mean & sd_stdv
    void update_sd_lambda() { sd_lambda = pow(sd_mean, 3.0) / pow(sd_stdv, 2.0); }

    // update sd_stdv based on sd_mean & sd_lambda
    void update_sd_stdv() { sd_stdv = pow(pow(sd_mean, 3.0) / sd_lambda, .5); }

    // update logs
    void update_logs()
    {
        log_level_mean = std::log(level_mean);
        log_level_stdv = std::log(level_stdv);
        log_sd_mean = std::log(sd_mean);
        log_sd_lambda = std::log(sd_lambda);
    }

    void scale(const Pore_Model_Parameters_Type& params, const Pore_Model_Parameters_Type& log_params)
    {
        // these functions are provided by ONT
        level_mean = level_mean * params.scale + params.shift;
        level_stdv = level_stdv * params.var;
        sd_mean = sd_mean * params.scale_sd;
        sd_lambda = sd_lambda * params.var_sd;
        update_sd_stdv();
        log_level_mean = std::log(level_mean);
        log_level_stdv += log_params.var;
        log_sd_mean += log_params.scale_sd;
        log_sd_lambda += log_params.var_sd;
    }

    Float_Type log_pr_emission(const Event_Type& e) const
    {
        return (log_normal_pdf< Float_Type >(e.mean, level_mean, level_stdv, log_level_stdv)
                + log_invgauss_pdf< Float_Type >(e.stdv, e.log_stdv, sd_mean, sd_lambda, log_sd_lambda));
    }
    Float_Type log_pr_corrected_emission(const Event_Type& e) const
    {
        return (log_normal_pdf< Float_Type >(e.corrected_mean, level_mean, level_stdv, log_level_stdv)
                + log_invgauss_pdf< Float_Type >(e.stdv, e.log_stdv, sd_mean, sd_lambda, log_sd_lambda));
    }

    friend std::ostream& operator << (std::ostream& os, const Pore_Model_State& state)
    {
        os << std::string(state.kmer.begin(), state.kmer.end()) << '\t'
           << state.level_mean << '\t'
           << state.level_stdv << '\t'
           << state.sd_mean << '\t'
           << state.sd_stdv;
        return os;
    }
}; // struct Pore_Model_State

template < typename Float_Type, unsigned Kmer_Size = 6 >
class Pore_Model
{
public:
    typedef Kmer< Kmer_Size > Kmer_Type;
    typedef Event< Float_Type, Kmer_Size > Event_Type;
    typedef Pore_Model_State< Float_Type, Kmer_Size > Pore_Model_State_Type;
    typedef Pore_Model_Parameters< Float_Type > Pore_Model_Parameters_Type;
    static const unsigned n_states = 1u << (2 * Kmer_Size);

    Pore_Model() : _strand(2) {}
    void clear() { _state.clear(); }

    const Pore_Model_State_Type& state(unsigned i) const { return _state.at(i); }
    Pore_Model_State_Type& state(unsigned i) { return _state.at(i); }

    const std::vector< Pore_Model_State_Type >& get_state_vector() const { return _state; }

    const unsigned& strand() const { return _strand; }
    unsigned& strand() { return _strand; }
    Float_Type mean() const { return _mean; }
    Float_Type stdv() const { return _stdv; }

    void scale(const Pore_Model_Parameters_Type& params)
    {
        Pore_Model_Parameters_Type log_params;
        log_params.var = std::log(params.var);
        log_params.scale_sd = std::log(params.scale_sd);
        log_params.var_sd = std::log(params.var_sd);
        for(unsigned i = 0; i < n_states; ++i)
        {
            state(i).scale(params, log_params);
        }
        update_statistics();
    }

    // load model from fast5 file
    void load_from_fast5(const fast5::File& f, bool strand)
    {
        assert(f.have_basecall_model(strand));
        auto m = f.get_basecall_model(strand);
        assert(m.size() == n_states);
        _state.clear();
        _state.reserve(n_states);
        for (unsigned i = 0; i < n_states; ++i)
        {
            _state.emplace_back();
            state(i) = m.at(i);
        }
        update_statistics();
    }

    // load from vector
    template < typename V_Float_Type >
    void load_from_vector(const std::vector< V_Float_Type >& v)
    {
        assert(v.size() == n_states * 4);
        _state.clear();
        _state.reserve(n_states);
        for (unsigned i = 0; i < n_states; ++i)
        {
            _state.emplace_back();
            state(i).level_mean = v[4 * i + 0];
            state(i).level_stdv = v[4 * i + 1];
            state(i).sd_mean = v[4 * i + 2];
            state(i).sd_stdv = v[4 * i + 3];
            auto s = Kmer_Type::to_string(i);
            std::copy_n(s.begin(), Kmer_Size, state(i).kmer.begin());
            state(i).update_sd_lambda();
            state(i).update_logs();
        }
        update_statistics();
    }

    // write model to out stream
    friend std::ostream& operator << (std::ostream& os, const Pore_Model& pm)
    {
        for (unsigned i = 0; i < pm.n_states; ++i)
        {
            os << pm.state(i) << std::endl;
        }
        return os;
    }
    // load model from input stream
    friend std::istream& operator >> (std::istream& is, Pore_Model& pm)
    {
        pm._state.clear();
        pm._state.reserve(n_states);
        unsigned i = 0;
        std::string line;
        while (std::getline(is, line))
        {
            std::istringstream iss(line);
            std::string s;
            iss >> s;
            if (s[0] == '#') continue;
            if (line.find("kmer") != std::string::npos) continue;
            pm._state.emplace_back();
            iss >> pm.state(i).level_mean
                >> pm.state(i).level_stdv
                >> pm.state(i).sd_mean
                >> pm.state(i).sd_stdv;
            std::copy_n(s.begin(), Kmer_Size, pm.state(i).kmer.begin());
            pm.state(i).update_sd_lambda();
            pm.state(i).update_logs();
            ++i;
        }
        if (i != pm.n_states)
        {
            LOG(error)
                << "unexpected number of states" << std::endl;
            std::exit(EXIT_FAILURE);
        }
        std::sort(
            pm._state.begin(),
            pm._state.end(),
            [] (const Pore_Model_State_Type& lhs, const Pore_Model_State_Type& rhs)
            {
                return lhs.kmer < rhs.kmer;
            });
        for (unsigned i = 0; i < pm.n_states; ++i)
        {
            assert(Kmer_Type::to_int(pm.state(i).kmer) == i);
        }
        pm.update_statistics();
        return is;
    }

    // log of probability of an emission from a state
    Float_Type log_pr_emission(unsigned i, const Event_Type& e) const
    {
        Float_Type res = state(i).log_pr_emission(e);
        return res;
    }
    Float_Type log_pr_corrected_emission(unsigned i, const Event_Type& e) const
    {
        Float_Type res = state(i).log_pr_corrected_emission(e);
        return res;
    }

private:
    std::vector< Pore_Model_State_Type > _state;
    Float_Type _mean;
    Float_Type _stdv;
    unsigned _strand;

    void update_statistics()
    {
        assert(_state.size() == n_states);
        std::tie(_mean, _stdv) = alg::mean_stdv_of< Float_Type >(
            _state,
            [] (const Pore_Model_State_Type& s) { return s.level_mean; });
    }
}; // class Pore_Model

template < typename Float_Type, unsigned Kmer_Size >
using Pore_Model_Dict = std::map< std::string, Pore_Model< Float_Type, Kmer_Size > >;

#endif
<commit_msg>fix for gcc 4.8<commit_after>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish_poremodel -- Representation of the Oxford
// Nanopore sequencing model, as described in a FAST5 file
//
#ifndef __POREMODEL_HPP
#define __POREMODEL_HPP

#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>

#include "Kmer.hpp"
#include "Event.hpp"
#include "fast5.hpp"
#include "alg.hpp"

template < typename Float_Type >
inline Float_Type log_normal_pdf(Float_Type x, Float_Type mean, Float_Type stdv, Float_Type log_stdv)
{
    // From SO: http://stackoverflow.com/questions/10847007/using-the-gaussian-probability-density-function-in-c
    static const Float_Type log_2pi = std::log(2.0 * M_PI);
    Float_Type a = (x - mean) / stdv;
    return - log_stdv - (log_2pi + a * a) / static_cast< Float_Type >(2.0);
}

template < typename Float_Type >
inline Float_Type log_invgauss_pdf(Float_Type x, Float_Type log_x,
                                   Float_Type mu, Float_Type lambda, Float_Type log_lambda)
{
    static const Float_Type log_2pi = std::log(2.0 * M_PI);
    Float_Type a = (x - mu) / mu;
    return (log_lambda - log_2pi - static_cast< Float_Type >(3.0) * log_x - lambda * a * a / x) / static_cast< Float_Type >(2.0);
}

template < typename Float_Type >
struct Pore_Model_Parameters
{
    Pore_Model_Parameters() : scale(1.0), shift(0.0), drift(0.0), var(1.0), scale_sd(1.0), var_sd(1.0) {}

    Float_Type scale;
    Float_Type shift;
    Float_Type drift;
    Float_Type var;
    Float_Type scale_sd;
    Float_Type var_sd;

    void load_from_fast5(const fast5::File& f, bool strand)
    {
        assert(f.have_basecall_model(strand));
        auto m_p = f.get_basecall_model_params(strand);
        scale = m_p.scale;
        shift = m_p.shift;
        drift = m_p.drift;
        var = m_p.var;
        scale_sd = m_p.scale_sd;
        var_sd = m_p.var_sd;
    }

    friend std::ostream& operator << (std::ostream& os, const Pore_Model_Parameters& p)
    {
        os << "[scale=" << p.scale << " shift=" << p.shift << " drift=" << p.drift
           << " var=" << p.var << " scale_sd=" << p.scale_sd << " var_sd=" << p.var_sd << "]";
        return os;
    }
    void write_tsv(std::ostream& os) const
    {
        os << std::fixed << std::setprecision(5)
           << scale << '\t' << shift << '\t' << drift << '\t' << var << '\t' << scale_sd << '\t' << var_sd;
    }
}; // struct Pore_Model_Parameters

template < typename Float_Type, unsigned Kmer_Size >
struct Pore_Model_State
{
    typedef Event< Float_Type, Kmer_Size > Event_Type;
    typedef Pore_Model_Parameters< Float_Type > Pore_Model_Parameters_Type;

    Float_Type level_mean;
    Float_Type level_stdv;
    Float_Type sd_mean;
    Float_Type sd_stdv;
    Float_Type sd_lambda;

    Float_Type log_level_mean;
    Float_Type log_level_stdv;
    Float_Type log_sd_mean;
    Float_Type log_sd_stdv;
    Float_Type log_sd_lambda;

    std::array< char, Kmer_Size > kmer;

    Pore_Model_State& operator = (const fast5::Model_Entry& e)
    {
        level_mean = e.level_mean;
        level_stdv = e.level_stdv;
        sd_mean = e.sd_mean;
        sd_stdv = e.sd_stdv;
        std::copy_n(e.kmer.begin(), Kmer_Size, kmer.begin());
        update_sd_lambda();
        update_logs();
        return *this;
    }

    // update sd_lambda based on sd_mean & sd_stdv
    void update_sd_lambda() { sd_lambda = pow(sd_mean, 3.0) / pow(sd_stdv, 2.0); }

    // update sd_stdv based on sd_mean & sd_lambda
    void update_sd_stdv() { sd_stdv = pow(pow(sd_mean, 3.0) / sd_lambda, .5); }

    // update logs
    void update_logs()
    {
        log_level_mean = std::log(level_mean);
        log_level_stdv = std::log(level_stdv);
        log_sd_mean = std::log(sd_mean);
        log_sd_lambda = std::log(sd_lambda);
    }

    void scale(const Pore_Model_Parameters_Type& params, const Pore_Model_Parameters_Type& log_params)
    {
        // these functions are provided by ONT
        level_mean = level_mean * params.scale + params.shift;
        level_stdv = level_stdv * params.var;
        sd_mean = sd_mean * params.scale_sd;
        sd_lambda = sd_lambda * params.var_sd;
        update_sd_stdv();
        log_level_mean = std::log(level_mean);
        log_level_stdv += log_params.var;
        log_sd_mean += log_params.scale_sd;
        log_sd_lambda += log_params.var_sd;
    }

    Float_Type log_pr_emission(const Event_Type& e) const
    {
        return (log_normal_pdf< Float_Type >(e.mean, level_mean, level_stdv, log_level_stdv)
                + log_invgauss_pdf< Float_Type >(e.stdv, e.log_stdv, sd_mean, sd_lambda, log_sd_lambda));
    }
    Float_Type log_pr_corrected_emission(const Event_Type& e) const
    {
        return (log_normal_pdf< Float_Type >(e.corrected_mean, level_mean, level_stdv, log_level_stdv)
                + log_invgauss_pdf< Float_Type >(e.stdv, e.log_stdv, sd_mean, sd_lambda, log_sd_lambda));
    }

    friend std::ostream& operator << (std::ostream& os, const Pore_Model_State& state)
    {
        os << std::string(state.kmer.begin(), state.kmer.end()) << '\t'
           << state.level_mean << '\t'
           << state.level_stdv << '\t'
           << state.sd_mean << '\t'
           << state.sd_stdv;
        return os;
    }

    friend bool operator < (const Pore_Model_State& lhs, const Pore_Model_State& rhs)
    {
        return lhs.kmer < rhs.kmer;
    }
}; // struct Pore_Model_State

template < typename Float_Type, unsigned Kmer_Size = 6 >
class Pore_Model
{
public:
    typedef Kmer< Kmer_Size > Kmer_Type;
    typedef Event< Float_Type, Kmer_Size > Event_Type;
    typedef Pore_Model_State< Float_Type, Kmer_Size > Pore_Model_State_Type;
    typedef Pore_Model_Parameters< Float_Type > Pore_Model_Parameters_Type;
    static const unsigned n_states = 1u << (2 * Kmer_Size);

    Pore_Model() : _strand(2) {}
    void clear() { _state.clear(); }

    const Pore_Model_State_Type& state(unsigned i) const { return _state.at(i); }
    Pore_Model_State_Type& state(unsigned i) { return _state.at(i); }

    const std::vector< Pore_Model_State_Type >& get_state_vector() const { return _state; }

    const unsigned& strand() const { return _strand; }
    unsigned& strand() { return _strand; }
    Float_Type mean() const { return _mean; }
    Float_Type stdv() const { return _stdv; }

    void scale(const Pore_Model_Parameters_Type& params)
    {
        Pore_Model_Parameters_Type log_params;
        log_params.var = std::log(params.var);
        log_params.scale_sd = std::log(params.scale_sd);
        log_params.var_sd = std::log(params.var_sd);
        for(unsigned i = 0; i < n_states; ++i)
        {
            state(i).scale(params, log_params);
        }
        update_statistics();
    }

    // load model from fast5 file
    void load_from_fast5(const fast5::File& f, bool strand)
    {
        assert(f.have_basecall_model(strand));
        auto m = f.get_basecall_model(strand);
        assert(m.size() == n_states);
        _state.clear();
        _state.reserve(n_states);
        for (unsigned i = 0; i < n_states; ++i)
        {
            _state.emplace_back();
            state(i) = m.at(i);
        }
        update_statistics();
    }

    // load from vector
    template < typename V_Float_Type >
    void load_from_vector(const std::vector< V_Float_Type >& v)
    {
        assert(v.size() == n_states * 4);
        _state.clear();
        _state.reserve(n_states);
        for (unsigned i = 0; i < n_states; ++i)
        {
            _state.emplace_back();
            state(i).level_mean = v[4 * i + 0];
            state(i).level_stdv = v[4 * i + 1];
            state(i).sd_mean = v[4 * i + 2];
            state(i).sd_stdv = v[4 * i + 3];
            auto s = Kmer_Type::to_string(i);
            std::copy_n(s.begin(), Kmer_Size, state(i).kmer.begin());
            state(i).update_sd_lambda();
            state(i).update_logs();
        }
        update_statistics();
    }

    // write model to out stream
    friend std::ostream& operator << (std::ostream& os, const Pore_Model& pm)
    {
        for (unsigned i = 0; i < pm.n_states; ++i)
        {
            os << pm.state(i) << std::endl;
        }
        return os;
    }
    // load model from input stream
    friend std::istream& operator >> (std::istream& is, Pore_Model& pm)
    {
        pm._state.clear();
        pm._state.reserve(n_states);
        unsigned i = 0;
        std::string line;
        while (std::getline(is, line))
        {
            std::istringstream iss(line);
            std::string s;
            iss >> s;
            if (s[0] == '#') continue;
            if (line.find("kmer") != std::string::npos) continue;
            pm._state.emplace_back();
            iss >> pm.state(i).level_mean
                >> pm.state(i).level_stdv
                >> pm.state(i).sd_mean
                >> pm.state(i).sd_stdv;
            std::copy_n(s.begin(), Kmer_Size, pm.state(i).kmer.begin());
            pm.state(i).update_sd_lambda();
            pm.state(i).update_logs();
            ++i;
        }
        if (i != pm.n_states)
        {
            LOG(error)
                << "unexpected number of states" << std::endl;
            std::exit(EXIT_FAILURE);
        }
        std::sort(pm._state.begin(), pm._state.end());
        for (unsigned i = 0; i < pm.n_states; ++i)
        {
            assert(Kmer_Type::to_int(pm.state(i).kmer) == i);
        }
        pm.update_statistics();
        return is;
    }

    // log of probability of an emission from a state
    Float_Type log_pr_emission(unsigned i, const Event_Type& e) const
    {
        Float_Type res = state(i).log_pr_emission(e);
        return res;
    }
    Float_Type log_pr_corrected_emission(unsigned i, const Event_Type& e) const
    {
        Float_Type res = state(i).log_pr_corrected_emission(e);
        return res;
    }

private:
    std::vector< Pore_Model_State_Type > _state;
    Float_Type _mean;
    Float_Type _stdv;
    unsigned _strand;

    void update_statistics()
    {
        assert(_state.size() == n_states);
        std::tie(_mean, _stdv) = alg::mean_stdv_of< Float_Type >(
            _state,
            [] (const Pore_Model_State_Type& s) { return s.level_mean; });
    }
}; // class Pore_Model

template < typename Float_Type, unsigned Kmer_Size >
using Pore_Model_Dict = std::map< std::string, Pore_Model< Float_Type, Kmer_Size > >;

#endif
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include <QtGui/QComboBox>
#include <QtGui/QHBoxLayout>
#include <QtGui/QButtonGroup>
#include <QtGui/QPushButton>
#include <QtGui/QLabel>

#include "notificationwidgets.h"

#include <QtDebug>

NotificationActionsWidget::NotificationActionsWidget(const QStringList& actions, QWidget *parent)
    : QWidget(parent),
      m_comboBox(0)
{
    QHash<uint,QString> actionMap;

    bool ok;
    for (int i = 0; i < actions.count(); ++i)
    {
        uint id = actions.at(i).toInt(&ok);
        if (!ok)
        {
            qDebug() << "NotificationActionsWidget id has to be number, got:" << actions.at(i) << "Actions:" << actions;
        }
        else if (i == actions.count()-1)
        {
            qDebug() << "NotificationActionsWidget actions has contains pairs (id, value, id, value...) got odd count:" << actions.count() << "Actions:" << actions;
        }
        else
        {
            actionMap[id] = actions.at(i+1);
        }
        ++i; // move to the next ID
    }

    qDebug() << "NotificationActionsWidget processed actions:" << actionMap;

    // Let's be a little bit tricky here. Let's allow only few
    // buttons in the layout. We will use a combobox if there
    // are more actions. I think it's more user friendly.
    QHashIterator<uint,QString> it(actionMap);
    QHBoxLayout *l = new QHBoxLayout();
    setLayout(l);
    if (actionMap.count() < 4)
    {
        QButtonGroup *group = new QButtonGroup(this);

        while (it.hasNext())
        {
            it.next();
            QPushButton *b = new QPushButton(it.value(), this);
            l->addWidget(b);
            group->addButton(b, it.key());
        }
        connect(group, SIGNAL(buttonClicked(QAbstractButton*)),
                this, SIGNAL(actionTriggered(QAbstractButton*)));
    }
    else
    {
        l->addWidget(new QLabel(tr("Actions:"), this));
        m_comboBox = new QComboBox(this);
        while (it.hasNext())
        {
            it.next();
            m_comboBox->addItem(it.value(), it.key());
        }
        l->addWidget(m_comboBox);
        QPushButton *b = new QPushButton(tr("OK"), this);
        connect(b, SIGNAL(clicked()),
                this, SLOT(actionComboBoxActivated()));
    }
}

void NotificationActionsWidget::actionComboBoxActivated()
{
    if (!m_comboBox)
        return;
    int ix = m_comboBox->currentIndex();
    if (ix == -1)
        return;
    emit actionTriggered(m_comboBox->itemText(ix));
}

void NotificationActionsWidget::actionButtonActivated(QAbstractButton* button)
{
    emit actionTriggered(button->text());
}
<commit_msg>slot name fix<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include <QtGui/QComboBox>
#include <QtGui/QHBoxLayout>
#include <QtGui/QButtonGroup>
#include <QtGui/QPushButton>
#include <QtGui/QLabel>

#include "notificationwidgets.h"

#include <QtDebug>

NotificationActionsWidget::NotificationActionsWidget(const QStringList& actions, QWidget *parent)
    : QWidget(parent),
      m_comboBox(0)
{
    QHash<uint,QString> actionMap;

    bool ok;
    for (int i = 0; i < actions.count(); ++i)
    {
        uint id = actions.at(i).toInt(&ok);
        if (!ok)
        {
            qDebug() << "NotificationActionsWidget id has to be number, got:" << actions.at(i) << "Actions:" << actions;
        }
        else if (i == actions.count()-1)
        {
            qDebug() << "NotificationActionsWidget actions has contains pairs (id, value, id, value...) got odd count:" << actions.count() << "Actions:" << actions;
        }
        else
        {
            actionMap[id] = actions.at(i+1);
        }
        ++i; // move to the next ID
    }

    qDebug() << "NotificationActionsWidget processed actions:" << actionMap;

    // Let's be a little bit tricky here. Let's allow only few
    // buttons in the layout. We will use a combobox if there
    // are more actions. I think it's more user friendly.
    QHashIterator<uint,QString> it(actionMap);
    QHBoxLayout *l = new QHBoxLayout();
    setLayout(l);
    if (actionMap.count() < 4)
    {
        QButtonGroup *group = new QButtonGroup(this);

        while (it.hasNext())
        {
            it.next();
            QPushButton *b = new QPushButton(it.value(), this);
            l->addWidget(b);
            group->addButton(b, it.key());
        }
        connect(group, SIGNAL(buttonClicked(QAbstractButton*)),
                this, SIGNAL(actionButtonActivated(QAbstractButton*)));
    }
    else
    {
        l->addWidget(new QLabel(tr("Actions:"), this));
        m_comboBox = new QComboBox(this);
        while (it.hasNext())
        {
            it.next();
            m_comboBox->addItem(it.value(), it.key());
        }
        l->addWidget(m_comboBox);
        QPushButton *b = new QPushButton(tr("OK"), this);
        connect(b, SIGNAL(clicked()),
                this, SLOT(actionComboBoxActivated()));
    }
}

void NotificationActionsWidget::actionComboBoxActivated()
{
    if (!m_comboBox)
        return;
    int ix = m_comboBox->currentIndex();
    if (ix == -1)
        return;
    emit actionTriggered(m_comboBox->itemText(ix));
}

void NotificationActionsWidget::actionButtonActivated(QAbstractButton* button)
{
    emit actionTriggered(button->text());
}
<|endoftext|>


<commit_before>// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include <nvcore/StrLib.h>
#include <nvcore/StdStream.h>

#include <nvimage/Image.h>
#include <nvimage/DirectDrawSurface.h>

#include <nvtt/nvtt.h>

#include "cmdline.h"

#include <time.h> // clock

//#define WINDOWS_LEAN_AND_MEAN
//#include <windows.h> // TIMER

struct MyOutputHandler : public nvtt::OutputHandler
{
	MyOutputHandler(const char * name) : total(0), progress(0), percentage(0), stream(new nv::StdOutputStream(name)) {}
	virtual ~MyOutputHandler() { delete stream; }

	void setTotal(int64 t)
	{
		total = t + 128;
	}
	void setDisplayProgress(bool b)
	{
		verbose = b;
	}

	virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
	{
		// ignore.
	}

	// Output data.
	virtual bool writeData(const void * data, int size)
	{
		nvDebugCheck(stream != NULL);
		stream->serialize(const_cast<void *>(data), size);

		progress += size;
		int p = int((100 * progress) / total);
		if (verbose && p != percentage)
		{
			nvCheck(p >= 0);

			percentage = p;
			printf("\r%d%%", percentage);
			fflush(stdout);
		}

		return true;
	}

	int64 total;
	int64 progress;
	int percentage;
	bool verbose;
	nv::StdOutputStream * stream;
};

struct MyErrorHandler : public nvtt::ErrorHandler
{
	virtual void error(nvtt::Error e)
	{
		nvDebugBreak();
	}
};

// Set color to normal map conversion options.
void setColorToNormalMap(nvtt::InputOptions & inputOptions)
{
	inputOptions.setNormalMap(false);
	inputOptions.setConvertToNormalMap(true);
	inputOptions.setHeightEvaluation(1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f, 0.0f);
	//inputOptions.setNormalFilter(1.0f, 0, 0, 0);
	//inputOptions.setNormalFilter(0.0f, 0, 0, 1);
	inputOptions.setGamma(1.0f, 1.0f);
	inputOptions.setNormalizeMipmaps(true);
}

// Set options for normal maps.
void setNormalMap(nvtt::InputOptions & inputOptions)
{
	inputOptions.setNormalMap(true);
	inputOptions.setConvertToNormalMap(false);
	inputOptions.setGamma(1.0f, 1.0f);
	inputOptions.setNormalizeMipmaps(true);
}

// Set options for color maps.
void setColorMap(nvtt::InputOptions & inputOptions)
{
	inputOptions.setNormalMap(false);
	inputOptions.setConvertToNormalMap(false);
	inputOptions.setGamma(2.2f, 2.2f);
	inputOptions.setNormalizeMipmaps(false);
}

int main(int argc, char *argv[])
{
	MyAssertHandler assertHandler;
	MyMessageHandler messageHandler;

	bool normal = false;
	bool color2normal = false;
	bool wrapRepeat = false;
	bool noMipmaps = false;
	bool fast = false;
	bool nocuda = false;
	bool silent = false;
	bool bc1n = false;
	nvtt::Format format = nvtt::Format_BC1;
	bool premultiplyAlpha = false;

	const char * externalCompressor = NULL;

	nv::Path input;
	nv::Path output;

	// Parse arguments.
	for (int i = 1; i < argc; i++)
	{
		// Input options.
		if (strcmp("-color", argv[i]) == 0)
		{
		}
		else if (strcmp("-normal", argv[i]) == 0)
		{
			normal = true;
		}
		else if (strcmp("-tonormal", argv[i]) == 0)
		{
			color2normal = true;
		}
		else if (strcmp("-clamp", argv[i]) == 0)
		{
		}
		else if (strcmp("-repeat", argv[i]) == 0)
		{
			wrapRepeat = true;
		}
		else if (strcmp("-nomips", argv[i]) == 0)
		{
			noMipmaps = true;
		}
		else if (strcmp("-premula", argv[i]) == 0)
		{
			premultiplyAlpha = true;
		}

		// Compression options.
		else if (strcmp("-fast", argv[i]) == 0)
		{
			fast = true;
		}
		else if (strcmp("-nocuda", argv[i]) == 0)
		{
			nocuda = true;
		}
		else if (strcmp("-rgb", argv[i]) == 0)
		{
			format = nvtt::Format_RGB;
		}
		else if (strcmp("-bc1", argv[i]) == 0)
		{
			format = nvtt::Format_BC1;
		}
		else if (strcmp("-bc1n", argv[i]) == 0)
		{
			format = nvtt::Format_BC1;
			bc1n = true;
		}
		else if (strcmp("-bc1a", argv[i]) == 0)
		{
			format = nvtt::Format_BC1a;
		}
		else if (strcmp("-bc2", argv[i]) == 0)
		{
			format = nvtt::Format_BC2;
		}
		else if (strcmp("-bc3", argv[i]) == 0)
		{
			format = nvtt::Format_BC3;
		}
		else if (strcmp("-bc3n", argv[i]) == 0)
		{
			format = nvtt::Format_BC3n;
		}
		else if (strcmp("-bc4", argv[i]) == 0)
		{
			format = nvtt::Format_BC4;
		}
		else if (strcmp("-bc5", argv[i]) == 0)
		{
			format = nvtt::Format_BC5;
		}

		// Undocumented option. Mainly used for testing.
		else if (strcmp("-ext", argv[i]) == 0)
		{
			if (i+1 < argc && argv[i+1][0] != '-') {
				externalCompressor = argv[i+1];
				i++;
			}
		}

		// Misc options
		else if (strcmp("-silent", argv[i]) == 0)
		{
			silent = true;
		}

		else if (argv[i][0] != '-')
		{
			input = argv[i];

			if (i+1 < argc && argv[i+1][0] != '-') {
				output = argv[i+1];
			}
			else
			{
				output.copy(input.str());
				output.stripExtension();
				output.append(".dds");
			}

			break;
		}
	}

	printf("NVIDIA Texture Tools - Copyright NVIDIA Corporation 2007\n\n");

	if (input.isNull())
	{
		printf("usage: nvcompress [options] infile [outfile]\n\n");

		printf("Input options:\n");
		printf("  -color   \tThe input image is a color map (default).\n");
		printf("  -normal  \tThe input image is a normal map.\n");
		printf("  -tonormal\tConvert input to normal map.\n");
		printf("  -clamp   \tClamp wrapping mode (default).\n");
		printf("  -repeat  \tRepeat wrapping mode.\n");
		printf("  -nomips  \tDisable mipmap generation.\n");
		printf("  -premula \tPremultiply alpha into color channel.\n\n");

		printf("Compression options:\n");
		printf("  -fast    \tFast compression.\n");
		printf("  -nocuda  \tDo not use cuda compressor.\n");
		printf("  -rgb     \tRGBA format\n");
		printf("  -bc1     \tBC1 format (DXT1)\n");
		printf("  -bc1n    \tBC1 normal map format (DXT1nm)\n");
		printf("  -bc1a    \tBC1 format with binary alpha (DXT1a)\n");
		printf("  -bc2     \tBC2 format (DXT3)\n");
		printf("  -bc3     \tBC3 format (DXT5)\n");
		printf("  -bc3n    \tBC3 normal map format (DXT5nm)\n");
		printf("  -bc4     \tBC4 format (ATI1)\n");
		printf("  -bc5     \tBC5 format (3Dc/ATI2)\n\n");

		return 1;
	}

	// @@ Make sure input file exists.

	// Set input options.
	nvtt::InputOptions inputOptions;

	if (nv::strCaseCmp(input.extension(), ".dds") == 0)
	{
		// Load surface.
		nv::DirectDrawSurface dds(input);
		if (!dds.isValid())
		{
			fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
			return 1;
		}

		if (!dds.isSupported() || dds.isTexture3D())
		{
			fprintf(stderr, "The file '%s' is not a supported DDS file.\n", input.str());
			return 1;
		}

		uint faceCount;
		if (dds.isTexture2D())
		{
			inputOptions.setTextureLayout(nvtt::TextureType_2D, dds.width(), dds.height());
			faceCount = 1;
		}
		else
		{
			nvDebugCheck(dds.isTextureCube());
			inputOptions.setTextureLayout(nvtt::TextureType_Cube, dds.width(), dds.height());
			faceCount = 6;
		}

		uint mipmapCount = dds.mipmapCount();

		nv::Image mipmap;

		for (uint f = 0; f < faceCount; f++)
		{
			for (uint m = 0; m < mipmapCount; m++)
			{
				dds.mipmap(&mipmap, f, m);

				inputOptions.setMipmapData(mipmap.pixels(), mipmap.width(), mipmap.height(), 1, f, m);
			}
		}
	}
	else
	{
		// Regular image.
		nv::Image image;
		if (!image.load(input))
		{
			fprintf(stderr, "The file '%s' is not a supported image type.\n", input.str());
			return 1;
		}

		inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height());
		inputOptions.setMipmapData(image.pixels(), image.width(), image.height());
	}

	if (wrapRepeat)
	{
		inputOptions.setWrapMode(nvtt::WrapMode_Repeat);
	}
	else
	{
		inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
	}

	if (normal)
	{
		setNormalMap(inputOptions);
	}
	else if (color2normal)
	{
		setColorToNormalMap(inputOptions);
	}
	else
	{
		setColorMap(inputOptions);
	}

	if (noMipmaps)
	{
		inputOptions.setMipmapGeneration(false);
	}

	if (premultiplyAlpha)
	{
		inputOptions.setPremultiplyAlpha(true);
		inputOptions.setAlphaMode(nvtt::AlphaMode_Premultiplied);
	}

	nvtt::CompressionOptions compressionOptions;
	compressionOptions.setFormat(format);
	if (fast)
	{
		compressionOptions.setQuality(nvtt::Quality_Fastest);
	}
	else
	{
		compressionOptions.setQuality(nvtt::Quality_Normal);
		//compressionOptions.setQuality(nvtt::Quality_Production);
		//compressionOptions.setQuality(nvtt::Quality_Highest);
	}

	if (bc1n)
	{
		compressionOptions.setColorWeights(1, 1, 0);
	}

	if (externalCompressor != NULL)
	{
		compressionOptions.setExternalCompressor(externalCompressor);
	}

	MyErrorHandler errorHandler;
	MyOutputHandler outputHandler(output);
	if (outputHandler.stream->isError())
	{
		fprintf(stderr, "Error opening '%s' for writting\n", output.str());
		return 1;
	}

	nvtt::Compressor compressor;
	compressor.enableCudaAcceleration(!nocuda);

	outputHandler.setTotal(compressor.estimateSize(inputOptions, compressionOptions));
	outputHandler.setDisplayProgress(!silent);

	nvtt::OutputOptions outputOptions;
	//outputOptions.setFileName(output);
	outputOptions.setOutputHandler(&outputHandler);
	outputOptions.setErrorHandler(&errorHandler);

//	printf("Press ENTER.\n");
//	fflush(stdout);
//	getchar();

/*	LARGE_INTEGER temp;
	QueryPerformanceFrequency((LARGE_INTEGER*) &temp);
	double freq = ((double) temp.QuadPart) / 1000.0;

    LARGE_INTEGER start_time;
    QueryPerformanceCounter((LARGE_INTEGER*) &start_time);
*/
	clock_t start = clock();

	compressor.process(inputOptions, compressionOptions, outputOptions);
/*
	LARGE_INTEGER end_time;
	QueryPerformanceCounter((LARGE_INTEGER*) &end_time);

	float diff_time = (float) (((double) end_time.QuadPart - (double) start_time.QuadPart) / freq);
	printf("\rtime taken: %.3f seconds\n", diff_time/1000);
*/

	clock_t end = clock();
	printf("\rtime taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);

	return 0;
}

<commit_msg>Add -mipfilter command line option, per request of Noel Llopis.<commit_after>// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include <nvcore/StrLib.h>
#include <nvcore/StdStream.h>

#include <nvimage/Image.h>
#include <nvimage/DirectDrawSurface.h>

#include <nvtt/nvtt.h>

#include "cmdline.h"

#include <time.h> // clock

//#define WINDOWS_LEAN_AND_MEAN
//#include <windows.h> // TIMER

struct MyOutputHandler : public nvtt::OutputHandler
{
	MyOutputHandler(const char * name) : total(0), progress(0), percentage(0), stream(new nv::StdOutputStream(name)) {}
	virtual ~MyOutputHandler() { delete stream; }

	void setTotal(int64 t)
	{
		total = t + 128;
	}
	void setDisplayProgress(bool b)
	{
		verbose = b;
	}

	virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
	{
		// ignore.
	}

	// Output data.
	virtual bool writeData(const void * data, int size)
	{
		nvDebugCheck(stream != NULL);
		stream->serialize(const_cast<void *>(data), size);

		progress += size;
		int p = int((100 * progress) / total);
		if (verbose && p != percentage)
		{
			nvCheck(p >= 0);

			percentage = p;
			printf("\r%d%%", percentage);
			fflush(stdout);
		}

		return true;
	}

	int64 total;
	int64 progress;
	int percentage;
	bool verbose;
	nv::StdOutputStream * stream;
};

struct MyErrorHandler : public nvtt::ErrorHandler
{
	virtual void error(nvtt::Error e)
	{
		nvDebugBreak();
	}
};

// Set color to normal map conversion options.
void setColorToNormalMap(nvtt::InputOptions & inputOptions)
{
	inputOptions.setNormalMap(false);
	inputOptions.setConvertToNormalMap(true);
	inputOptions.setHeightEvaluation(1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f, 0.0f);
	//inputOptions.setNormalFilter(1.0f, 0, 0, 0);
	//inputOptions.setNormalFilter(0.0f, 0, 0, 1);
	inputOptions.setGamma(1.0f, 1.0f);
	inputOptions.setNormalizeMipmaps(true);
}

// Set options for normal maps.
void setNormalMap(nvtt::InputOptions & inputOptions)
{
	inputOptions.setNormalMap(true);
	inputOptions.setConvertToNormalMap(false);
	inputOptions.setGamma(1.0f, 1.0f);
	inputOptions.setNormalizeMipmaps(true);
}

// Set options for color maps.
void setColorMap(nvtt::InputOptions & inputOptions)
{
	inputOptions.setNormalMap(false);
	inputOptions.setConvertToNormalMap(false);
	inputOptions.setGamma(2.2f, 2.2f);
	inputOptions.setNormalizeMipmaps(false);
}

int main(int argc, char *argv[])
{
	MyAssertHandler assertHandler;
	MyMessageHandler messageHandler;

	bool normal = false;
	bool color2normal = false;
	bool wrapRepeat = false;
	bool noMipmaps = false;
	bool fast = false;
	bool nocuda = false;
	bool silent = false;
	bool bc1n = false;
	nvtt::Format format = nvtt::Format_BC1;
	bool premultiplyAlpha = false;
	nvtt::MipmapFilter mipmapFilter = nvtt::MipmapFilter_Box;

	const char * externalCompressor = NULL;

	nv::Path input;
	nv::Path output;

	// Parse arguments.
	for (int i = 1; i < argc; i++)
	{
		// Input options.
		if (strcmp("-color", argv[i]) == 0)
		{
		}
		else if (strcmp("-normal", argv[i]) == 0)
		{
			normal = true;
		}
		else if (strcmp("-tonormal", argv[i]) == 0)
		{
			color2normal = true;
		}
		else if (strcmp("-clamp", argv[i]) == 0)
		{
		}
		else if (strcmp("-repeat", argv[i]) == 0)
		{
			wrapRepeat = true;
		}
		else if (strcmp("-nomips", argv[i]) == 0)
		{
			noMipmaps = true;
		}
		else if (strcmp("-premula", argv[i]) == 0)
		{
			premultiplyAlpha = true;
		}
		else if (strcmp("-mipfilter", argv[i]) == 0)
		{
			if (i+1 == argc) break;
			i++;

			if (strcmp("box", argv[i]) == 0) mipmapFilter = nvtt::MipmapFilter_Box;
			else if (strcmp("triangle", argv[i]) == 0) mipmapFilter = nvtt::MipmapFilter_Triangle;
			else if (strcmp("kaiser", argv[i]) == 0) mipmapFilter = nvtt::MipmapFilter_Kaiser;
		}

		// Compression options.
		else if (strcmp("-fast", argv[i]) == 0)
		{
			fast = true;
		}
		else if (strcmp("-nocuda", argv[i]) == 0)
		{
			nocuda = true;
		}
		else if (strcmp("-rgb", argv[i]) == 0)
		{
			format = nvtt::Format_RGB;
		}
		else if (strcmp("-bc1", argv[i]) == 0)
		{
			format = nvtt::Format_BC1;
		}
		else if (strcmp("-bc1n", argv[i]) == 0)
		{
			format = nvtt::Format_BC1;
			bc1n = true;
		}
		else if (strcmp("-bc1a", argv[i]) == 0)
		{
			format = nvtt::Format_BC1a;
		}
		else if (strcmp("-bc2", argv[i]) == 0)
		{
			format = nvtt::Format_BC2;
		}
		else if (strcmp("-bc3", argv[i]) == 0)
		{
			format = nvtt::Format_BC3;
		}
		else if (strcmp("-bc3n", argv[i]) == 0)
		{
			format = nvtt::Format_BC3n;
		}
		else if (strcmp("-bc4", argv[i]) == 0)
		{
			format = nvtt::Format_BC4;
		}
		else if (strcmp("-bc5", argv[i]) == 0)
		{
			format = nvtt::Format_BC5;
		}

		// Undocumented option. Mainly used for testing.
		else if (strcmp("-ext", argv[i]) == 0)
		{
			if (i+1 < argc && argv[i+1][0] != '-') {
				externalCompressor = argv[i+1];
				i++;
			}
		}

		// Misc options
		else if (strcmp("-silent", argv[i]) == 0)
		{
			silent = true;
		}

		else if (argv[i][0] != '-')
		{
			input = argv[i];

			if (i+1 < argc && argv[i+1][0] != '-') {
				output = argv[i+1];
			}
			else
			{
				output.copy(input.str());
				output.stripExtension();
				output.append(".dds");
			}

			break;
		}
	}

	printf("NVIDIA Texture Tools - Copyright NVIDIA Corporation 2007\n\n");

	if (input.isNull())
	{
		printf("usage: nvcompress [options] infile [outfile]\n\n");

		printf("Input options:\n");
		printf("  -color   \tThe input image is a color map (default).\n");
		printf("  -normal  \tThe input image is a normal map.\n");
		printf("  -tonormal\tConvert input to normal map.\n");
		printf("  -clamp   \tClamp wrapping mode (default).\n");
		printf("  -repeat  \tRepeat wrapping mode.\n");
		printf("  -nomips  \tDisable mipmap generation.\n");
		printf("  -premula \tPremultiply alpha into color channel.\n");
		printf("  -mipfilter \tMipmap filter. One of the following: box, triangle, kaiser.\n\n");

		printf("Compression options:\n");
		printf("  -fast    \tFast compression.\n");
		printf("  -nocuda  \tDo not use cuda compressor.\n");
		printf("  -rgb     \tRGBA format\n");
		printf("  -bc1     \tBC1 format (DXT1)\n");
		printf("  -bc1n    \tBC1 normal map format (DXT1nm)\n");
		printf("  -bc1a    \tBC1 format with binary alpha (DXT1a)\n");
		printf("  -bc2     \tBC2 format (DXT3)\n");
		printf("  -bc3     \tBC3 format (DXT5)\n");
		printf("  -bc3n    \tBC3 normal map format (DXT5nm)\n");
		printf("  -bc4     \tBC4 format (ATI1)\n");
		printf("  -bc5     \tBC5 format (3Dc/ATI2)\n\n");

		return 1;
	}

	// @@ Make sure input file exists.

	// Set input options.
	nvtt::InputOptions inputOptions;

	if (nv::strCaseCmp(input.extension(), ".dds") == 0)
	{
		// Load surface.
		nv::DirectDrawSurface dds(input);
		if (!dds.isValid())
		{
			fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
			return 1;
		}

		if (!dds.isSupported() || dds.isTexture3D())
		{
			fprintf(stderr, "The file '%s' is not a supported DDS file.\n", input.str());
			return 1;
		}

		uint faceCount;
		if (dds.isTexture2D())
		{
			inputOptions.setTextureLayout(nvtt::TextureType_2D, dds.width(), dds.height());
			faceCount = 1;
		}
		else
		{
			nvDebugCheck(dds.isTextureCube());
			inputOptions.setTextureLayout(nvtt::TextureType_Cube, dds.width(), dds.height());
			faceCount = 6;
		}

		uint mipmapCount = dds.mipmapCount();

		nv::Image mipmap;

		for (uint f = 0; f < faceCount; f++)
		{
			for (uint m = 0; m < mipmapCount; m++)
			{
				dds.mipmap(&mipmap, f, m);

				inputOptions.setMipmapData(mipmap.pixels(), mipmap.width(), mipmap.height(), 1, f, m);
			}
		}
	}
	else
	{
		// Regular image.
		nv::Image image;
		if (!image.load(input))
		{
			fprintf(stderr, "The file '%s' is not a supported image type.\n", input.str());
			return 1;
		}

		inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height());
		inputOptions.setMipmapData(image.pixels(), image.width(), image.height());
	}

	if (wrapRepeat)
	{
		inputOptions.setWrapMode(nvtt::WrapMode_Repeat);
	}
	else
	{
		inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
	}

	if (normal)
	{
		setNormalMap(inputOptions);
	}
	else if (color2normal)
	{
		setColorToNormalMap(inputOptions);
	}
	else
	{
		setColorMap(inputOptions);
	}

	if (noMipmaps)
	{
		inputOptions.setMipmapGeneration(false);
	}

	if (premultiplyAlpha)
	{
		inputOptions.setPremultiplyAlpha(true);
		inputOptions.setAlphaMode(nvtt::AlphaMode_Premultiplied);
	}

	inputOptions.setMipmapFilter(mipmapFilter);

	nvtt::CompressionOptions compressionOptions;
	compressionOptions.setFormat(format);
	if (fast)
	{
		compressionOptions.setQuality(nvtt::Quality_Fastest);
	}
	else
	{
		compressionOptions.setQuality(nvtt::Quality_Normal);
		//compressionOptions.setQuality(nvtt::Quality_Production);
		//compressionOptions.setQuality(nvtt::Quality_Highest);
	}

	if (bc1n)
	{
		compressionOptions.setColorWeights(1, 1, 0);
	}

	if (externalCompressor != NULL)
	{
		compressionOptions.setExternalCompressor(externalCompressor);
	}

	MyErrorHandler errorHandler;
	MyOutputHandler outputHandler(output);
	if (outputHandler.stream->isError())
	{
		fprintf(stderr, "Error opening '%s' for writting\n", output.str());
		return 1;
	}

	nvtt::Compressor compressor;
	compressor.enableCudaAcceleration(!nocuda);

	outputHandler.setTotal(compressor.estimateSize(inputOptions, compressionOptions));
	outputHandler.setDisplayProgress(!silent);

	nvtt::OutputOptions outputOptions;
	//outputOptions.setFileName(output);
	outputOptions.setOutputHandler(&outputHandler);
	outputOptions.setErrorHandler(&errorHandler);

//	printf("Press ENTER.\n");
//	fflush(stdout);
//	getchar();

/*	LARGE_INTEGER temp;
	QueryPerformanceFrequency((LARGE_INTEGER*) &temp);
	double freq = ((double) temp.QuadPart) / 1000.0;

    LARGE_INTEGER start_time;
    QueryPerformanceCounter((LARGE_INTEGER*) &start_time);
*/
	clock_t start = clock();

	compressor.process(inputOptions, compressionOptions, outputOptions);
/*
	LARGE_INTEGER end_time;
	QueryPerformanceCounter((LARGE_INTEGER*) &end_time);

	float diff_time = (float) (((double) end_time.QuadPart - (double) start_time.QuadPart) / freq);
	printf("\rtime taken: %.3f seconds\n", diff_time/1000);
*/

	clock_t end = clock();
	printf("\rtime taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);

	return 0;
}

<|endoftext|>