<commit_before>#include <glib/gstdio.h>

#include <fstream>
#include <iostream>

#include "settings.h"
using namespace AhoViewer;

#include "config.h"

SettingsManager AhoViewer::Settings;

SettingsManager::SettingsManager()
  : ConfigPath(Glib::build_filename(Glib::get_user_config_dir(), PACKAGE)),
    ConfigFilePath(Glib::build_filename(ConfigPath, PACKAGE ".cfg")),
    BooruPath(Glib::build_filename(ConfigPath, "booru")),
    FavoriteTagsPath(Glib::build_filename(ConfigPath, "favorite-tags")),
// Defaults {{{
    DefaultBools(
    {
        { "AutoOpenArchive",      true  },
        { "MangaMode",            true  },
        { "RememberLastFile",     true  },
        { "RememberLastSavePath", true  },
        { "SaveThumbnails",       true  },
        { "StartFullscreen",      false },
        { "StoreRecentFiles",     true  },
        { "SmartNavigation",      false },

        { "BooruBrowserVisible",  true  },
        { "MenuBarVisible",       true  },
        { "ScrollbarsVisible",    true  },
        { "StatusBarVisible",     true  },
        { "ThumbnailBarVisible",  false },
        { "HideAll",              false },
        { "HideAllFullscreen",    true  },
    }),
    DefaultInts(
    {
        { "ArchiveIndex",     -1  },
        { "CacheSize",        2   },
        { "SlideshowDelay",   5   },
        { "CursorHideDelay",  2   },
        { "TagViewPosition",  560 },
        { "SelectedBooru",    0   },
        { "BooruLimit",       50  },
        { "BooruWidth",       -1  },
    }),
    DefaultSites(
    {
        std::make_tuple("Gelbooru",   "http://gelbooru.com",         Booru::Site::Type::GELBOORU),
        std::make_tuple("Danbooru",   "https://danbooru.donmai.us",  Booru::Site::Type::DANBOORU),
        std::make_tuple("Konachan",   "http://konachan.com",         Booru::Site::Type::MOEBOORU),
        std::make_tuple("yande.re",   "https://yande.re",            Booru::Site::Type::MOEBOORU),
        std::make_tuple("Safebooru",  "http://safebooru.org",        Booru::Site::Type::GELBOORU),
    }),
    DefaultKeybindings(
    {
        {
            "File",
            {
                { "OpenFile",            "<Primary>o" },
                { "Preferences",         "p"          },
                { "Close",               "<Primary>w" },
                { "Quit",                "<Primary>q" },
            }
        },
        {
            "ViewMode",
            {
                { "ToggleMangaMode",     "g" },
                { "AutoFitMode",         "a" },
                { "FitWidthMode",        "w" },
                { "FitHeightMode",       "h" },
                { "ManualZoomMode",      "m" },
            }
        },
        {
            "UserInterface",
            {
                { "ToggleFullscreen",    "f"          },
                { "ToggleMenuBar",       "<Primary>m" },
                { "ToggleStatusBar",     "<Primary>b" },
                { "ToggleScrollbars",    "<Primary>l" },
                { "ToggleThumbnailBar",  "t"          },
                { "ToggleBooruBrowser",  "b"          },
                { "ToggleHideAll",       "i"          },
            }
        },
        {
            "Zoom",
            {
                { "ZoomIn",              "<Primary>equal" },
                { "ZoomOut",             "<Primary>minus" },
                { "ResetZoom",           "<Primary>0"     },
            }
        },
        {
            "Navigation",
            {
                { "NextImage",           "Page_Down" },
                { "PreviousImage",       "Page_Up"   },
                { "FirstImage",          "Home"      },
                { "LastImage",           "End"       },
                { "ToggleSlideshow",     "s"         },
            }
        },
        {
            "Scroll",
            {
                { "ScrollUp",            "Up"    },
                { "ScrollDown",          "Down"  },
                { "ScrollLeft",          "Left"  },
                { "ScrollRight",         "Right" },
            }
        },
        {
            "BooruBrowser",
            {
                { "NewTab",              "<Primary>t"        },
                { "SaveImage",           "<Primary>s"        },
                { "SaveImages",          "<Primary><Shift>s" },
                { "ViewPost",            "<Primary><Shift>o" },
                { "CopyImageURL",        "y"                 },
            }
        }
    }),
    DefaultBGColor("#161616")
// }}}
{
    Config.setTabWidth(4); // this is very important
    if (Glib::file_test(ConfigFilePath, Glib::FILE_TEST_EXISTS))
    {
        try
        {
            Config.readFile(ConfigFilePath.c_str());
        }
        catch (const libconfig::ParseException &ex)
        {
            std::cerr << "libconfig::Config.readFile: " << ex.what() << std::endl;
        }
    }

    if (!Glib::file_test(BooruPath, Glib::FILE_TEST_EXISTS))
        g_mkdir_with_parents(BooruPath.c_str(), 0700);

    if (Glib::file_test(FavoriteTagsPath, Glib::FILE_TEST_EXISTS))
    {
        std::ifstream ifs(FavoriteTagsPath);

        if (ifs)
            std::copy(std::istream_iterator<std::string>(ifs),
                      std::istream_iterator<std::string>(),
                      std::inserter(m_FavoriteTags, m_FavoriteTags.begin()));
    }

    load_keybindings();
}

SettingsManager::~SettingsManager()
{
    try
    {
        Config.writeFile(ConfigFilePath.c_str());
    }
    catch (const libconfig::FileIOException &ex)
    {
        std::cerr << "libconfig::Config.writeFile: " << ex.what() << std::endl;
    }

    if (!m_FavoriteTags.empty())
    {
        std::ofstream ofs(FavoriteTagsPath);

        if (ofs)
            std::copy(m_FavoriteTags.begin(), m_FavoriteTags.end(),
                    std::ostream_iterator<std::string>(ofs, "\n"));
    }
    else if (Glib::file_test(FavoriteTagsPath, Glib::FILE_TEST_EXISTS))
    {
        g_unlink(FavoriteTagsPath.c_str());
    }
}

bool SettingsManager::get_bool(const std::string &key) const
{
    if (Config.exists(key))
        return Config.lookup(key);

    return DefaultBools.at(key);
}

int SettingsManager::get_int(const std::string &key) const
{
    if (Config.exists(key))
        return Config.lookup(key);

    return DefaultInts.at(key);
}

std::string SettingsManager::get_string(const std::string &key) const
{
    if (Config.exists(key))
        return (const char*)Config.lookup(key);

    return "";
}

std::vector<std::shared_ptr<Booru::Site>>& SettingsManager::get_sites()
{
    if (m_Sites.size())
    {
        return m_Sites;
    }
    else if (Config.exists("Sites"))
    {
        const Setting &sites = Config.lookup("Sites");
        if (sites.getLength() > 0)
        {
            for (size_t i = 0; i < static_cast<size_t>(sites.getLength()); ++i)
            {
                const Setting &s = sites[i];
                m_Sites.push_back(std::make_shared<Booru::Site>(s["name"], s["url"],
                            static_cast<Booru::Site::Type>(static_cast<int>(s["type"]))));
            }

            return m_Sites;
        }
    }
    else
    {
        for (const std::tuple<std::string, std::string, Booru::Site::Type> &s : DefaultSites)
            m_Sites.push_back(std::make_shared<Booru::Site>(
                        std::get<0>(s), std::get<1>(s), std::get<2>(s)));
    }

    return m_Sites;
}

void SettingsManager::update_sites()
{
    remove("Sites");
    Setting &sites = Config.getRoot().add("Sites", Setting::TypeList);

    for (const std::shared_ptr<Booru::Site> &s : m_Sites)
    {
        Setting &site = sites.add(Setting::TypeGroup);
        set("name", s->get_name(), Setting::TypeString, site);
        set("url", s->get_url(), Setting::TypeString, site);
        set("type", static_cast<int>(s->get_type()), Setting::TypeInt, site);
    }
}

bool SettingsManager::get_geometry(int &x, int &y, int &w, int &h) const
{
    if (Config.lookupValue("Geometry.x", x) && Config.lookupValue("Geometry.y", y) &&
        Config.lookupValue("Geometry.w", w) && Config.lookupValue("Geometry.h", h))
    {
        return true;
    }

    return false;
}

void SettingsManager::set_geometry(const int x, const int y, const int w, const int h)
{
    if (!Config.exists("Geometry"))
        Config.getRoot().add("Geometry", Setting::TypeGroup);

    Setting &geo = Config.lookup("Geometry");

    set("x", x, Setting::TypeInt, geo);
    set("y", y, Setting::TypeInt, geo);
    set("w", w, Setting::TypeInt, geo);
    set("h", h, Setting::TypeInt, geo);
}

std::string SettingsManager::get_keybinding(const std::string &group, const std::string &name) const
{
    return m_Keybindings.at(group).at(name);
}

/**
 * Clears the first (only) binding that has the same value as value
 * Sets the group and name parameters to those of the binding that was cleared
 * Returns true if it actually cleared a binding
 **/
bool SettingsManager::clear_keybinding(const std::string &value, std::string &group, std::string &name)
{
    for (const std::pair<std::string, std::map<std::string, std::string>> &i : m_Keybindings)
    {
        for (const std::pair<std::string, std::string> &j : i.second)
        {
            if (j.second == value)
            {
                group = i.first;
                name = j.first;

                set_keybinding(group, name, "");

                return true;
            }
        }
    }

    return false;
}

void SettingsManager::set_keybinding(const std::string &group, const std::string &name, const std::string &value)
{
    if (!Config.exists("Keybindings"))
        Config.getRoot().add("Keybindings", Setting::TypeGroup);

    Setting &keys = Config.lookup("Keybindings");

    if (!keys.exists(group))
        keys.add(group, Setting::TypeGroup);

    set(name, value, Setting::TypeString, keys[group.c_str()]);
    m_Keybindings[group][name] = value;
}

std::string SettingsManager::reset_keybinding(const std::string &group, const std::string &name)
{
    if (Config.exists("Keybindings"))
    {
        Setting &keys = Config.lookup("Keybindings");

        if (keys.exists(group) && keys[group.c_str()].exists(name))
            keys[group.c_str()].remove(name);
    }

    return m_Keybindings[group][name] = DefaultKeybindings.at(group).at(name);
}

Gdk::Color SettingsManager::get_background_color() const
{
    if (Config.exists("BackgroundColor"))
        return Gdk::Color((const char*)Config.lookup("BackgroundColor"));

    return DefaultBGColor;
}

void SettingsManager::set_background_color(const Gdk::Color &value)
{
    set("BackgroundColor", value.to_string());
}

Booru::Site::Rating SettingsManager::get_booru_max_rating() const
{
    if (Config.exists("BooruMaxRating"))
        return Booru::Site::Rating(static_cast<int>(Config.lookup("BooruMaxRating")));

    return DefaultBooruMaxRating;
}

void SettingsManager::set_booru_max_rating(const Booru::Site::Rating value)
{
    set("BooruMaxRating", static_cast<int>(value));
}

ImageBox::ZoomMode SettingsManager::get_zoom_mode() const
{
    if (Config.exists("ZoomMode"))
        return ImageBox::ZoomMode(((const char*)Config.lookup("ZoomMode"))[0]);

    return DefaultZoomMode;
}

void SettingsManager::set_zoom_mode(const ImageBox::ZoomMode value)
{
    set("ZoomMode", std::string(1, static_cast<char>(value)));
}

void SettingsManager::remove(const std::string &key)
{
    if (Config.exists(key))
        Config.getRoot().remove(key);
}

void SettingsManager::load_keybindings()
{
    if (Config.exists("Keybindings"))
    {
        Setting &keys = Config.lookup("Keybindings");

        for (const std::pair<std::string, std::map<std::string, std::string>> &i : DefaultKeybindings)
        {
            if (keys.exists(i.first))
            {
                for (const std::pair<std::string, std::string> &j : i.second)
                {
                    if (keys[i.first.c_str()].exists(j.first))
                    {
                        m_Keybindings[i.first][j.first] = std::string(keys[i.first.c_str()][j.first.c_str()].c_str());
                    }
                    else
                    {
                        m_Keybindings[i.first][j.first] = DefaultKeybindings.at(i.first).at(j.first);
                    }
                }
            }
            else
            {
                m_Keybindings[i.first] = DefaultKeybindings.at(i.first);
            }
        }
    }
    else
    {
        m_Keybindings = DefaultKeybindings;
    }
}
<commit_msg>settings: Make Danbooru the default selected booru site<commit_after>#include <glib/gstdio.h>

#include <fstream>
#include <iostream>

#include "settings.h"
using namespace AhoViewer;

#include "config.h"

SettingsManager AhoViewer::Settings;

SettingsManager::SettingsManager()
  : ConfigPath(Glib::build_filename(Glib::get_user_config_dir(), PACKAGE)),
    ConfigFilePath(Glib::build_filename(ConfigPath, PACKAGE ".cfg")),
    BooruPath(Glib::build_filename(ConfigPath, "booru")),
    FavoriteTagsPath(Glib::build_filename(ConfigPath, "favorite-tags")),
// Defaults {{{
    DefaultBools(
    {
        { "AutoOpenArchive",      true  },
        { "MangaMode",            true  },
        { "RememberLastFile",     true  },
        { "RememberLastSavePath", true  },
        { "SaveThumbnails",       true  },
        { "StartFullscreen",      false },
        { "StoreRecentFiles",     true  },
        { "SmartNavigation",      false },

        { "BooruBrowserVisible",  true  },
        { "MenuBarVisible",       true  },
        { "ScrollbarsVisible",    true  },
        { "StatusBarVisible",     true  },
        { "ThumbnailBarVisible",  false },
        { "HideAll",              false },
        { "HideAllFullscreen",    true  },
    }),
    DefaultInts(
    {
        { "ArchiveIndex",     -1  },
        { "CacheSize",        2   },
        { "SlideshowDelay",   5   },
        { "CursorHideDelay",  2   },
        { "TagViewPosition",  560 },
        { "SelectedBooru",    0   },
        { "BooruLimit",       50  },
        { "BooruWidth",       -1  },
    }),
    DefaultSites(
    {
        // std::make_tuple("Gelbooru",   "http://gelbooru.com",         Booru::Site::Type::GELBOORU),
        std::make_tuple("Danbooru",   "https://danbooru.donmai.us",  Booru::Site::Type::DANBOORU),
        std::make_tuple("Konachan",   "http://konachan.com",         Booru::Site::Type::MOEBOORU),
        std::make_tuple("yande.re",   "https://yande.re",            Booru::Site::Type::MOEBOORU),
        std::make_tuple("Safebooru",  "http://safebooru.org",        Booru::Site::Type::GELBOORU),
    }),
    DefaultKeybindings(
    {
        {
            "File",
            {
                { "OpenFile",            "<Primary>o" },
                { "Preferences",         "p"          },
                { "Close",               "<Primary>w" },
                { "Quit",                "<Primary>q" },
            }
        },
        {
            "ViewMode",
            {
                { "ToggleMangaMode",     "g" },
                { "AutoFitMode",         "a" },
                { "FitWidthMode",        "w" },
                { "FitHeightMode",       "h" },
                { "ManualZoomMode",      "m" },
            }
        },
        {
            "UserInterface",
            {
                { "ToggleFullscreen",    "f"          },
                { "ToggleMenuBar",       "<Primary>m" },
                { "ToggleStatusBar",     "<Primary>b" },
                { "ToggleScrollbars",    "<Primary>l" },
                { "ToggleThumbnailBar",  "t"          },
                { "ToggleBooruBrowser",  "b"          },
                { "ToggleHideAll",       "i"          },
            }
        },
        {
            "Zoom",
            {
                { "ZoomIn",              "<Primary>equal" },
                { "ZoomOut",             "<Primary>minus" },
                { "ResetZoom",           "<Primary>0"     },
            }
        },
        {
            "Navigation",
            {
                { "NextImage",           "Page_Down" },
                { "PreviousImage",       "Page_Up"   },
                { "FirstImage",          "Home"      },
                { "LastImage",           "End"       },
                { "ToggleSlideshow",     "s"         },
            }
        },
        {
            "Scroll",
            {
                { "ScrollUp",            "Up"    },
                { "ScrollDown",          "Down"  },
                { "ScrollLeft",          "Left"  },
                { "ScrollRight",         "Right" },
            }
        },
        {
            "BooruBrowser",
            {
                { "NewTab",              "<Primary>t"        },
                { "SaveImage",           "<Primary>s"        },
                { "SaveImages",          "<Primary><Shift>s" },
                { "ViewPost",            "<Primary><Shift>o" },
                { "CopyImageURL",        "y"                 },
            }
        }
    }),
    DefaultBGColor("#161616")
// }}}
{
    Config.setTabWidth(4); // this is very important
    if (Glib::file_test(ConfigFilePath, Glib::FILE_TEST_EXISTS))
    {
        try
        {
            Config.readFile(ConfigFilePath.c_str());
        }
        catch (const libconfig::ParseException &ex)
        {
            std::cerr << "libconfig::Config.readFile: " << ex.what() << std::endl;
        }
    }

    if (!Glib::file_test(BooruPath, Glib::FILE_TEST_EXISTS))
        g_mkdir_with_parents(BooruPath.c_str(), 0700);

    if (Glib::file_test(FavoriteTagsPath, Glib::FILE_TEST_EXISTS))
    {
        std::ifstream ifs(FavoriteTagsPath);

        if (ifs)
            std::copy(std::istream_iterator<std::string>(ifs),
                      std::istream_iterator<std::string>(),
                      std::inserter(m_FavoriteTags, m_FavoriteTags.begin()));
    }

    load_keybindings();
}

SettingsManager::~SettingsManager()
{
    try
    {
        Config.writeFile(ConfigFilePath.c_str());
    }
    catch (const libconfig::FileIOException &ex)
    {
        std::cerr << "libconfig::Config.writeFile: " << ex.what() << std::endl;
    }

    if (!m_FavoriteTags.empty())
    {
        std::ofstream ofs(FavoriteTagsPath);

        if (ofs)
            std::copy(m_FavoriteTags.begin(), m_FavoriteTags.end(),
                    std::ostream_iterator<std::string>(ofs, "\n"));
    }
    else if (Glib::file_test(FavoriteTagsPath, Glib::FILE_TEST_EXISTS))
    {
        g_unlink(FavoriteTagsPath.c_str());
    }
}

bool SettingsManager::get_bool(const std::string &key) const
{
    if (Config.exists(key))
        return Config.lookup(key);

    return DefaultBools.at(key);
}

int SettingsManager::get_int(const std::string &key) const
{
    if (Config.exists(key))
        return Config.lookup(key);

    return DefaultInts.at(key);
}

std::string SettingsManager::get_string(const std::string &key) const
{
    if (Config.exists(key))
        return (const char*)Config.lookup(key);

    return "";
}

std::vector<std::shared_ptr<Booru::Site>>& SettingsManager::get_sites()
{
    if (m_Sites.size())
    {
        return m_Sites;
    }
    else if (Config.exists("Sites"))
    {
        const Setting &sites = Config.lookup("Sites");
        if (sites.getLength() > 0)
        {
            for (size_t i = 0; i < static_cast<size_t>(sites.getLength()); ++i)
            {
                const Setting &s = sites[i];
                m_Sites.push_back(std::make_shared<Booru::Site>(s["name"], s["url"],
                            static_cast<Booru::Site::Type>(static_cast<int>(s["type"]))));
            }

            return m_Sites;
        }
    }
    else
    {
        for (const std::tuple<std::string, std::string, Booru::Site::Type> &s : DefaultSites)
            m_Sites.push_back(std::make_shared<Booru::Site>(
                        std::get<0>(s), std::get<1>(s), std::get<2>(s)));
    }

    return m_Sites;
}

void SettingsManager::update_sites()
{
    remove("Sites");
    Setting &sites = Config.getRoot().add("Sites", Setting::TypeList);

    for (const std::shared_ptr<Booru::Site> &s : m_Sites)
    {
        Setting &site = sites.add(Setting::TypeGroup);
        set("name", s->get_name(), Setting::TypeString, site);
        set("url", s->get_url(), Setting::TypeString, site);
        set("type", static_cast<int>(s->get_type()), Setting::TypeInt, site);
    }
}

bool SettingsManager::get_geometry(int &x, int &y, int &w, int &h) const
{
    if (Config.lookupValue("Geometry.x", x) && Config.lookupValue("Geometry.y", y) &&
        Config.lookupValue("Geometry.w", w) && Config.lookupValue("Geometry.h", h))
    {
        return true;
    }

    return false;
}

void SettingsManager::set_geometry(const int x, const int y, const int w, const int h)
{
    if (!Config.exists("Geometry"))
        Config.getRoot().add("Geometry", Setting::TypeGroup);

    Setting &geo = Config.lookup("Geometry");

    set("x", x, Setting::TypeInt, geo);
    set("y", y, Setting::TypeInt, geo);
    set("w", w, Setting::TypeInt, geo);
    set("h", h, Setting::TypeInt, geo);
}

std::string SettingsManager::get_keybinding(const std::string &group, const std::string &name) const
{
    return m_Keybindings.at(group).at(name);
}

/**
 * Clears the first (only) binding that has the same value as value
 * Sets the group and name parameters to those of the binding that was cleared
 * Returns true if it actually cleared a binding
 **/
bool SettingsManager::clear_keybinding(const std::string &value, std::string &group, std::string &name)
{
    for (const std::pair<std::string, std::map<std::string, std::string>> &i : m_Keybindings)
    {
        for (const std::pair<std::string, std::string> &j : i.second)
        {
            if (j.second == value)
            {
                group = i.first;
                name = j.first;

                set_keybinding(group, name, "");

                return true;
            }
        }
    }

    return false;
}

void SettingsManager::set_keybinding(const std::string &group, const std::string &name, const std::string &value)
{
    if (!Config.exists("Keybindings"))
        Config.getRoot().add("Keybindings", Setting::TypeGroup);

    Setting &keys = Config.lookup("Keybindings");

    if (!keys.exists(group))
        keys.add(group, Setting::TypeGroup);

    set(name, value, Setting::TypeString, keys[group.c_str()]);
    m_Keybindings[group][name] = value;
}

std::string SettingsManager::reset_keybinding(const std::string &group, const std::string &name)
{
    if (Config.exists("Keybindings"))
    {
        Setting &keys = Config.lookup("Keybindings");

        if (keys.exists(group) && keys[group.c_str()].exists(name))
            keys[group.c_str()].remove(name);
    }

    return m_Keybindings[group][name] = DefaultKeybindings.at(group).at(name);
}

Gdk::Color SettingsManager::get_background_color() const
{
    if (Config.exists("BackgroundColor"))
        return Gdk::Color((const char*)Config.lookup("BackgroundColor"));

    return DefaultBGColor;
}

void SettingsManager::set_background_color(const Gdk::Color &value)
{
    set("BackgroundColor", value.to_string());
}

Booru::Site::Rating SettingsManager::get_booru_max_rating() const
{
    if (Config.exists("BooruMaxRating"))
        return Booru::Site::Rating(static_cast<int>(Config.lookup("BooruMaxRating")));

    return DefaultBooruMaxRating;
}

void SettingsManager::set_booru_max_rating(const Booru::Site::Rating value)
{
    set("BooruMaxRating", static_cast<int>(value));
}

ImageBox::ZoomMode SettingsManager::get_zoom_mode() const
{
    if (Config.exists("ZoomMode"))
        return ImageBox::ZoomMode(((const char*)Config.lookup("ZoomMode"))[0]);

    return DefaultZoomMode;
}

void SettingsManager::set_zoom_mode(const ImageBox::ZoomMode value)
{
    set("ZoomMode", std::string(1, static_cast<char>(value)));
}

void SettingsManager::remove(const std::string &key)
{
    if (Config.exists(key))
        Config.getRoot().remove(key);
}

void SettingsManager::load_keybindings()
{
    if (Config.exists("Keybindings"))
    {
        Setting &keys = Config.lookup("Keybindings");

        for (const std::pair<std::string, std::map<std::string, std::string>> &i : DefaultKeybindings)
        {
            if (keys.exists(i.first))
            {
                for (const std::pair<std::string, std::string> &j : i.second)
                {
                    if (keys[i.first.c_str()].exists(j.first))
                    {
                        m_Keybindings[i.first][j.first] = std::string(keys[i.first.c_str()][j.first.c_str()].c_str());
                    }
                    else
                    {
                        m_Keybindings[i.first][j.first] = DefaultKeybindings.at(i.first).at(j.first);
                    }
                }
            }
            else
            {
                m_Keybindings[i.first] = DefaultKeybindings.at(i.first);
            }
        }
    }
    else
    {
        m_Keybindings = DefaultKeybindings;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include "db/mail/MailSpool.h"

#include "db/io/ByteArrayInputStream.h"
#include "db/io/FileInputStream.h"
#include "db/io/FileOutputStream.h"
#include "db/data/Data.h"
#include "db/data/json/JsonReader.h"
#include "db/data/json/JsonWriter.h"
#include "db/mail/MailTemplateParser.h"

using namespace db::data::json;
using namespace db::io;
using namespace db::mail;
using namespace db::rt;

MailSpool::MailSpool() :
   mFile((FileImpl*)NULL)
{
   // spool empty thus far
   mHead = mTail = mCount = 0;
}

MailSpool::~MailSpool()
{
}

bool MailSpool::writeIndex()
{
   bool rval;

   // get associated index name
   std::string name = mFile->getAbsolutePath();
   name.append(".idx");
   File file(name.c_str());

   // write out index data
   FileOutputStream fos(file);
   DynamicObject config;
   config["head"] = mHead;
   config["tail"] = mTail;
   config["count"] = mCount;
   JsonWriter writer;
   rval = writer.write(config, &fos);
   fos.close();

   return rval;
}

void MailSpool::lock()
{
   mSpoolLock.lock();
}

void MailSpool::unlock()
{
   mSpoolLock.unlock();
}

bool MailSpool::setFile(File& file)
{
   bool rval;

   lock();
   {
      // set file
      mFile = file;

      // read associated index
      std::string name = mFile->getAbsolutePath();
      name.append(".idx");
      File file(name.c_str());
      if(!file->exists())
      {
         // create new spool index
         mHead = mTail = mCount = 0;
         rval = writeIndex();
      }
      else
      {
         // read existing spool index
         FileInputStream fis(file);
         JsonReader reader;
         DynamicObject config;
         reader.start(config);
         rval = reader.read(&fis) && reader.finish();
         fis.close();

         if(rval)
         {
            mHead = config["head"]->getUInt32();
            mTail = config["tail"]->getUInt32();
            mCount = config["count"]->getUInt32();
         }
      }
   }
   unlock();

   return rval;
}

bool MailSpool::spool(Mail* mail)
{
   bool rval;

   // convert mail to template
   std::string tpl = mail->toTemplate();

   lock();
   {
      // write out mail entry
      FileOutputStream fos(mFile, mCount > 0);

      // entry = index + size + tpl
      uint32_t idx = DB_UINT32_TO_LE(mTail);
      uint32_t size = DB_UINT32_TO_LE(tpl.length());
      rval =
         fos.write((char*)&idx, 4) &&
         fos.write((char*)&size, 4) &&
         fos.write(tpl.c_str(), tpl.length());
      fos.close();

      // increment tail, count
      mTail++;
      mCount++;

      // write out index
      rval = rval && writeIndex();
   }
   unlock();

   return rval;
}

bool MailSpool::getFirst(Mail* mail)
{
   bool rval = false;

   lock();
   {
      if(mCount == 0)
      {
         ExceptionRef e = new Exception(
            "Cannot get first mail from spool! Spool is empty!");
         Exception::setLast(e, false);
      }
      else
      {
         // read from spool file
         FileInputStream fis(mFile);
         char b[2048];
         int numBytes = 1;
         uint32_t idx;
         uint32_t size;

         // skip mail entries until head is reached
         while(numBytes > 0)
         {
            // read current index
            if((numBytes = fis.read(b, 4)) == 4)
            {
               memcpy(&idx, b, 4);
               idx = DB_UINT32_FROM_LE(idx);
            }

            // read current size
            if((numBytes = fis.read(b, 4) == 4))
            {
               memcpy(&size, b, 4);
               size = DB_UINT32_FROM_LE(size);
            }

            // read mail if current index is head
            if(idx == mHead)
            {
               // read mail data
               ByteBuffer bb(size);
               int read = (int)(size > 2048 ? 2048 : size);
               while(read > 0 && (numBytes = fis.read(b, read)) > 0)
               {
                  bb.put(b, numBytes, false);
                  size -= numBytes;
                  read = (int)(size > 2048 ? 2048 : size);
               }

               if(numBytes != -1)
               {
                  // parse mail data
                  ByteArrayInputStream bais(&bb, false);
                  MailTemplateParser parser;
                  DynamicObject vars;
                  rval = parser.parse(mail, vars, false, &bais);
               }
               break;
            }
            else
            {
               // skip mail data
               if(fis.skip(size) < 0)
               {
                  // error while skipping
                  numBytes = -1;
               }
            }
         }

         // close spool file
         fis.close();
      }
   }
   unlock();

   return rval;
}

bool MailSpool::unwind()
{
   bool rval;

   lock();
   {
      if(mCount == 0)
      {
         // nothing to do, spool is empty
         rval = true;
      }
      else
      {
         // increment head, decrement count
         mHead++;
         mCount--;

         if(mCount == 0)
         {
            // reset index, spool now empty
            mHead = mTail = 0;
            mFile->remove();
         }

         // write out index
         rval = writeIndex();
      }
   }
   unlock();

   return rval;
}

uint32_t MailSpool::getCount()
{
   return mCount;
}
<commit_msg>Added code to create necessary directories for mail spool file.<commit_after>/*
 * Copyright (c) 2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include "db/mail/MailSpool.h"

#include "db/io/ByteArrayInputStream.h"
#include "db/io/FileInputStream.h"
#include "db/io/FileOutputStream.h"
#include "db/data/Data.h"
#include "db/data/json/JsonReader.h"
#include "db/data/json/JsonWriter.h"
#include "db/mail/MailTemplateParser.h"

using namespace db::data::json;
using namespace db::io;
using namespace db::mail;
using namespace db::rt;

MailSpool::MailSpool() :
   mFile((FileImpl*)NULL)
{
   // spool empty thus far
   mHead = mTail = mCount = 0;
}

MailSpool::~MailSpool()
{
}

bool MailSpool::writeIndex()
{
   bool rval;

   // get associated index name
   std::string name = mFile->getAbsolutePath();
   name.append(".idx");
   File file(name.c_str());
   if((rval = file->mkdirs()))
   {
      // write out index data
      FileOutputStream fos(file);
      DynamicObject config;
      config["head"] = mHead;
      config["tail"] = mTail;
      config["count"] = mCount;
      JsonWriter writer;
      rval = writer.write(config, &fos);
      fos.close();
   }

   return rval;
}

void MailSpool::lock()
{
   mSpoolLock.lock();
}

void MailSpool::unlock()
{
   mSpoolLock.unlock();
}

bool MailSpool::setFile(File& file)
{
   bool rval;

   lock();
   {
      // set file
      mFile = file;

      // read associated index
      std::string name = mFile->getAbsolutePath();
      name.append(".idx");
      File file(name.c_str());
      if(!file->exists())
      {
         // create new spool index
         mHead = mTail = mCount = 0;
         rval = writeIndex();
      }
      else
      {
         // read existing spool index
         FileInputStream fis(file);
         JsonReader reader;
         DynamicObject config;
         reader.start(config);
         rval = reader.read(&fis) && reader.finish();
         fis.close();

         if(rval)
         {
            mHead = config["head"]->getUInt32();
            mTail = config["tail"]->getUInt32();
            mCount = config["count"]->getUInt32();
         }
      }
   }
   unlock();

   return rval;
}

bool MailSpool::spool(Mail* mail)
{
   bool rval;

   // convert mail to template
   std::string tpl = mail->toTemplate();

   lock();
   {
      // write out mail entry
      FileOutputStream fos(mFile, mCount > 0);

      // entry = index + size + tpl
      uint32_t idx = DB_UINT32_TO_LE(mTail);
      uint32_t size = DB_UINT32_TO_LE(tpl.length());
      rval =
         fos.write((char*)&idx, 4) &&
         fos.write((char*)&size, 4) &&
         fos.write(tpl.c_str(), tpl.length());
      fos.close();

      // increment tail, count
      mTail++;
      mCount++;

      // write out index
      rval = rval && writeIndex();
   }
   unlock();

   return rval;
}

bool MailSpool::getFirst(Mail* mail)
{
   bool rval = false;

   lock();
   {
      if(mCount == 0)
      {
         ExceptionRef e = new Exception(
            "Cannot get first mail from spool! Spool is empty!");
         Exception::setLast(e, false);
      }
      else
      {
         // read from spool file
         FileInputStream fis(mFile);
         char b[2048];
         int numBytes = 1;
         uint32_t idx;
         uint32_t size;

         // skip mail entries until head is reached
         while(numBytes > 0)
         {
            // read current index
            if((numBytes = fis.read(b, 4)) == 4)
            {
               memcpy(&idx, b, 4);
               idx = DB_UINT32_FROM_LE(idx);
            }

            // read current size
            if((numBytes = fis.read(b, 4) == 4))
            {
               memcpy(&size, b, 4);
               size = DB_UINT32_FROM_LE(size);
            }

            // read mail if current index is head
            if(idx == mHead)
            {
               // read mail data
               ByteBuffer bb(size);
               int read = (int)(size > 2048 ? 2048 : size);
               while(read > 0 && (numBytes = fis.read(b, read)) > 0)
               {
                  bb.put(b, numBytes, false);
                  size -= numBytes;
                  read = (int)(size > 2048 ? 2048 : size);
               }

               if(numBytes != -1)
               {
                  // parse mail data
                  ByteArrayInputStream bais(&bb, false);
                  MailTemplateParser parser;
                  DynamicObject vars;
                  rval = parser.parse(mail, vars, false, &bais);
               }
               break;
            }
            else
            {
               // skip mail data
               if(fis.skip(size) < 0)
               {
                  // error while skipping
                  numBytes = -1;
               }
            }
         }

         // close spool file
         fis.close();
      }
   }
   unlock();

   return rval;
}

bool MailSpool::unwind()
{
   bool rval;

   lock();
   {
      if(mCount == 0)
      {
         // nothing to do, spool is empty
         rval = true;
      }
      else
      {
         // increment head, decrement count
         mHead++;
         mCount--;

         if(mCount == 0)
         {
            // reset index, spool now empty
            mHead = mTail = 0;
            mFile->remove();
         }

         // write out index
         rval = writeIndex();
      }
   }
   unlock();

   return rval;
}

uint32_t MailSpool::getCount()
{
   return mCount;
}
<|endoftext|>


<commit_before>#include "shaders.h"

//#include "mathutils.h"

#define INVALID_SHADER 0

#define DEBUG_SHADER_ERRORS true

//
// AnyShader
//

AnyShader::AnyShader() {
    //empty
}

AnyShader::~AnyShader() {
    //empty
}

/**
 * Create the shader program.
 */
bool AnyShader::create() {
    if (failed) {
        return false;
    }

    if (prog != INVALID_PROGRAM) {
        return true;
    }

    //compile
    GLuint handle = glCreateProgram();

    if (handle == INVALID_PROGRAM) {
        error = "glCreateProgram failed.";

        return false;
    }

    if (!vertexShader.empty()) {
        GLuint vertShader = compileShader(vertexShader, GL_VERTEX_SHADER);

        if (vertShader == INVALID_SHADER) {
            //cleanup
            glDeleteProgram(handle);

            return false;
        }

        glAttachShader(handle, vertShader);
        glDeleteShader(vertShader);
    }

    if (!fragmentShader.empty()) {
        GLuint fragShader = compileShader(fragmentShader, GL_FRAGMENT_SHADER);

        if (fragShader == INVALID_SHADER) {
            //cleanup
            glDeleteProgram(handle);

            return false;
        }

        glAttachShader(handle, fragShader);
        glDeleteShader(fragShader);
    }

    //link
    glLinkProgram(handle);

    GLint linkStatus;

    glGetProgramiv(handle, GL_LINK_STATUS, &linkStatus);

    if (linkStatus == GL_FALSE) {
        //cleanup
        glDeleteProgram(handle);

        //get error
        GLchar messages[256];

        glGetProgramInfoLog(handle, sizeof(messages), 0, &messages[0]);

        if (DEBUG_SHADER_ERRORS) {
            printf("shader linking failed: %s\n", messages);
        }

        return false;
    }

    prog = handle;

    //initialize
    initShader();

    return true;
}

/**
 * Compile a shader.
 *
 * Note: sets error on failure.
 */
GLuint AnyShader::compileShader(std::string source, const GLenum type) {
    GLint compileStatus;
    GLuint handle = glCreateShader(type);

    if (handle == INVALID_SHADER) {
        error = "glCreateShader() failed";
        return -1;
    }

#ifdef RPI
    //add GLSL version
    source = "#version 100\n" + source;
#endif

    GLchar *src = (GLchar *)source.c_str();

    glShaderSource(handle, 1, (const GLchar **)&src, NULL);
    glCompileShader(handle);

    //get status
    glGetShaderiv(handle, GL_COMPILE_STATUS, &compileStatus);

    if (compileStatus == GL_FALSE) {
        //free
        glDeleteShader(handle);
        handle = INVALID_SHADER;

        //get error
        GLchar messages[256];

        glGetShaderInfoLog(handle, sizeof(messages), 0, &messages[0]);

        if (DEBUG_SHADER_ERRORS) {
            std::string typeStr;

            if (type == GL_VERTEX_SHADER) {
                typeStr = "vertex shader";
            } else if (type == GL_FRAGMENT_SHADER) {
                typeStr = "fragment shader";
            }

            printf("shader compilation error: %s\ntype: %s\n", messages, typeStr.c_str());
        }

        error = std::string(messages);
    }

    return handle;
}

/**
 * Destroy the shader.
 *
 * Note: has to be called in OpenGL thread.
 */
void AnyShader::destroy() {
    if (prog != INVALID_PROGRAM) {
        glDeleteProgram(prog);
        prog = INVALID_PROGRAM;
    }

    //reset failed
    failed = false;
}

/**
 * Get attribute location.
 */
GLint AnyShader::getAttributeLocation(std::string name) {
    GLint loc = glGetAttribLocation(prog, name.c_str());

    if (DEBUG_SHADER_ERRORS) {
        if (loc == -1) {
            printf("could not get location of attribute %s\n", name.c_str());
        }
    }

    return loc;
}

/**
 * Get uniform location.
 */
GLint AnyShader::getUniformLocation(std::string name) {
    GLint loc = glGetUniformLocation(prog, name.c_str());

    if (DEBUG_SHADER_ERRORS) {
        if (loc == -1) {
            printf("could not get location of uniform %s\n", name.c_str());
        }
    }

    return loc;
}

/**
 * Use the shader.
 *
 * Note: has to be called before any setters are used!
 */
void AnyShader::useShader(bool active) {
    if (!active) {
        glUseProgram(prog);
    }
}

//
// AnyAminoShader
//

AnyAminoShader::AnyAminoShader() : AnyShader() {
    //default vertex shader
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        attribute vec4 pos;

        void main() {
            gl_Position = mvp * trans * pos;
        }
    )";
}

/**
 * Initialize the shader.
 */
void AnyAminoShader::initShader() {
    useShader(false);

    //attributes
    aPos = getAttributeLocation("pos");

    //uniforms
    uMVP = getUniformLocation("mvp");
    uTrans = getUniformLocation("trans");
}

/**
 * Set transformation matrix.
 */
void AnyAminoShader::setTransformation(GLfloat modelView[16], GLfloat transition[16]) {
    glUniformMatrix4fv(uMVP, 1, GL_FALSE, modelView);
    glUniformMatrix4fv(uTrans, 1, GL_FALSE, transition);
}

/**
 * Set vertex data.
 */
void AnyAminoShader::setVertexData(GLsizei dim, GLfloat *vertices) {
    /*
     * Coords per vertex (2 or 3).
     *
     * Note: vertices is NULL in case of VBO usage
     */

    glVertexAttribPointer(aPos, dim, GL_FLOAT, GL_FALSE, 0, vertices);
}

/**
 * Draw triangles.
 */
void AnyAminoShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aPos);

    glDrawArrays(mode, 0, vertices);

    glDisableVertexAttribArray(aPos);
}

/**
 * Draw elements.
 */
void AnyAminoShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aPos);

    //Note: indices is offset in case of VBO
    glDrawElements(mode, elements, GL_UNSIGNED_SHORT, indices);

    glDisableVertexAttribArray(aPos);
}

//
// ColorShader
//

/**
 * Create color shader.
 */
ColorShader::ColorShader() : AnyAminoShader() {
    //shaders
    fragmentShader = R"(
        uniform vec4 color;

        void main() {
            gl_FragColor = color;
        }
    )";
}

/**
 * Initialize the color shader.
 */
void ColorShader::initShader() {
    AnyAminoShader::initShader();

    //uniforms
    uColor = getUniformLocation("color");
}

/**
 * Set color.
 */
void ColorShader::setColor(GLfloat color[4]) {
    glUniform4f(uColor, color[0], color[1], color[2], color[3]);
}

//
// ColorLightingShader
//

/**
 * Create color lighting shader.
 */
ColorLightingShader::ColorLightingShader() : ColorShader() {
    //shaders
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        //uniform mat4 normalMatrix;
        uniform vec3 lightDir;

        attribute vec4 pos;
        attribute vec3 normal;

        varying float lightFac;

        void main() {
            gl_Position = mvp * trans * pos;

            //simple version
            vec4 normalTrans = trans * vec4(normal, 0.);

            lightFac = abs(dot(normalTrans.xyz, -lightDir));

            //normalMatrix version
            //vec4 normalTrans = mvp * normalMatrix * vec4(normal, 1.);
            //lightFac = max(dot(normalTrans.xyz, -lightDir), 0.);
        }
    )";

    fragmentShader = R"(
        varying float lightFac;

        uniform vec4 color;

        void main() {
            gl_FragColor = vec4(color.rgb * lightFac, color.a);
        }
    )";
}

/**
 * Initialize the color lighting shader.
 */
void ColorLightingShader::initShader() {
    ColorShader::initShader();

    //attributes
    aNormal = getAttributeLocation("normal");

    //uniforms
    //uNormalMatrix = getUniformLocation("normalMatrix");
    uLightDir = getUniformLocation("lightDir");

    //default values
    GLfloat lightDir[3] = { 0, 0, -1 }; //parallel light on screen

    setLightDirection(lightDir);
}

/**
 * Set light direction.
 */
void ColorLightingShader::setLightDirection(GLfloat dir[3]) {
    glUniform3f(uLightDir, dir[0], dir[1], dir[2]);
}

/**
 * Set normal vectors.
 */
void ColorLightingShader::setNormalVectors(GLfloat *normals) {
    glVertexAttribPointer(aNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
}

/**
 * Set matrix.
 */
void ColorLightingShader::setTransformation(GLfloat modelView[16], GLfloat transition[16]) {
    AnyAminoShader::setTransformation(modelView, transition);

    //normal matrix
    /*
    GLfloat invMatrix[16];
    GLfloat normalMatrix[16];

    assert(invert_matrix(transition, invMatrix));
    transpose_matrix(normalMatrix, invMatrix);

    glUniformMatrix4fv(uNormalMatrix, 1, GL_FALSE, normalMatrix);
    */
}

/**
 * Draw triangles.
 */
void ColorLightingShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    AnyAminoShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aNormal);
}

/**
 * Draw elements.
 */
void ColorLightingShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    AnyAminoShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aNormal);
}

//
// TextureShader
//

TextureShader::TextureShader() : AnyAminoShader() {
    //shader
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        attribute vec4 pos;
        attribute vec2 texCoord;

        varying vec2 uv;

        void main() {
            gl_Position = mvp * trans * pos;
            uv = texCoord;
        }
    )";

    fragmentShader = R"(
        varying vec2 uv;

        uniform float opacity;
        uniform sampler2D tex;

        void main() {
            vec4 pixel = texture2D(tex, uv);

            gl_FragColor = vec4(pixel.rgb, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the color shader.
 */
void TextureShader::initShader() {
    AnyAminoShader::initShader();

    //attributes
    aTexCoord = getAttributeLocation("texCoord");

    //uniforms
    uOpacity = getUniformLocation("opacity");
    uTex = getUniformLocation("tex");

    //default values
    glUniform1i(uTex, 0); //GL_TEXTURE0
}

/**
 * Set opacity.
 */
void TextureShader::setOpacity(GLfloat opacity) {
    glUniform1f(uOpacity, opacity);
}

/**
 * Set texture coordinates.
 */
void TextureShader::setTextureCoordinates(GLfloat uv[][2]) {
    glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 0, uv);
}

/**
 * Draw texture.
 */
void TextureShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aTexCoord);

    glActiveTexture(GL_TEXTURE0);

    AnyAminoShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aTexCoord);
}

/**
 * Draw elements.
 */
void TextureShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aTexCoord);

    glActiveTexture(GL_TEXTURE0);

    AnyAminoShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aTexCoord);
}

//
// TextureClampToBorderShader
//

TextureClampToBorderShader::TextureClampToBorderShader() : TextureShader() {
    //Note: supports clamp to border, using transparent texture
    fragmentShader = R"(
        varying vec2 uv;

        uniform float opacity;
        uniform sampler2D tex;

        float clamp_to_border_factor(vec2 coords) {
            bvec2 out1 = greaterThan(coords, vec2(1, 1));
            bvec2 out2 = lessThan(coords, vec2(0, 0));
            bool do_clamp = (any(out1) || any(out2));

            return float(!do_clamp);
        }

        void main() {
            vec4 pixel = texture2D(tex, uv);

            gl_FragColor = vec4(pixel.rgb, pixel.a * opacity * clamp_to_border_factor(uv));
        }
    )";
}

//
// TextureLightingShader
//

/**
 * Create color lighting shader.
 */
TextureLightingShader::TextureLightingShader() : TextureShader() {
    //shaders
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        uniform vec3 lightDir;

        attribute vec4 pos;
        attribute vec2 texCoord;
        attribute vec3 normal;

        varying vec2 uv;
        varying float lightFac;

        void main() {
            gl_Position = mvp * trans * pos;

            uv = texCoord;

            vec4 normalTrans = trans * vec4(normal, 0.);

            //translucent layers
            lightFac = abs(dot(normalTrans.xyz, -lightDir));
        }
    )";

    fragmentShader = R"(
        varying vec2 uv;
        varying float lightFac;

        uniform float opacity;
        uniform sampler2D tex;

        void main() {
            vec4 pixel = texture2D(tex, uv);

            gl_FragColor = vec4(pixel.rgb * lightFac, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the color lighting shader.
 */
void TextureLightingShader::initShader() {
    TextureShader::initShader();

    //attributes
    aNormal = getAttributeLocation("normal");

    //uniforms
    //uNormalMatrix = getUniformLocation("normalMatrix");
    uLightDir = getUniformLocation("lightDir");

    //default values
    GLfloat lightDir[3] = { 0, 0, -1 }; //parallel light on screen

    setLightDirection(lightDir);
}

/**
 * Set light direction.
 */
void TextureLightingShader::setLightDirection(GLfloat dir[3]) {
    glUniform3f(uLightDir, dir[0], dir[1], dir[2]);
}

/**
 * Set normal vectors.
 */
void TextureLightingShader::setNormalVectors(GLfloat *normals) {
    glVertexAttribPointer(aNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
}

/**
 * Draw triangles.
 */
void TextureLightingShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    TextureShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aNormal);
}

/**
 * Draw elements.
 */
void TextureLightingShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    TextureShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aNormal);
}
<commit_msg>shader cleanup<commit_after>#include "shaders.h"

//#include "mathutils.h"

#define INVALID_SHADER 0

#define DEBUG_SHADER_ERRORS true

//
// AnyShader
//

AnyShader::AnyShader() {
    //empty
}

AnyShader::~AnyShader() {
    //empty
}

/**
 * Create the shader program.
 */
bool AnyShader::create() {
    if (failed) {
        return false;
    }

    if (prog != INVALID_PROGRAM) {
        return true;
    }

    //compile
    GLuint handle = glCreateProgram();

    if (handle == INVALID_PROGRAM) {
        error = "glCreateProgram failed.";

        return false;
    }

    if (!vertexShader.empty()) {
        GLuint vertShader = compileShader(vertexShader, GL_VERTEX_SHADER);

        if (vertShader == INVALID_SHADER) {
            //cleanup
            glDeleteProgram(handle);

            return false;
        }

        glAttachShader(handle, vertShader);
        glDeleteShader(vertShader);
    }

    if (!fragmentShader.empty()) {
        GLuint fragShader = compileShader(fragmentShader, GL_FRAGMENT_SHADER);

        if (fragShader == INVALID_SHADER) {
            //cleanup
            glDeleteProgram(handle);

            return false;
        }

        glAttachShader(handle, fragShader);
        glDeleteShader(fragShader);
    }

    //link
    glLinkProgram(handle);

    GLint linkStatus;

    glGetProgramiv(handle, GL_LINK_STATUS, &linkStatus);

    if (linkStatus == GL_FALSE) {
        //cleanup
        glDeleteProgram(handle);

        //get error
        GLchar messages[256];

        glGetProgramInfoLog(handle, sizeof(messages), 0, &messages[0]);

        if (DEBUG_SHADER_ERRORS) {
            printf("shader linking failed: %s\n", messages);
        }

        return false;
    }

    prog = handle;

    //initialize
    initShader();

    return true;
}

/**
 * Compile a shader.
 *
 * Note: sets error on failure.
 */
GLuint AnyShader::compileShader(std::string source, const GLenum type) {
    GLint compileStatus;
    GLuint handle = glCreateShader(type);

    if (handle == INVALID_SHADER) {
        error = "glCreateShader() failed";
        return -1;
    }

#ifdef RPI
    //add GLSL version
    source = "#version 100\n" + source;
#endif

    GLchar *src = (GLchar *)source.c_str();

    glShaderSource(handle, 1, (const GLchar **)&src, NULL);
    glCompileShader(handle);

    //get status
    glGetShaderiv(handle, GL_COMPILE_STATUS, &compileStatus);

    if (compileStatus == GL_FALSE) {
        //free
        glDeleteShader(handle);
        handle = INVALID_SHADER;

        //get error
        GLchar messages[256];

        glGetShaderInfoLog(handle, sizeof(messages), 0, &messages[0]);

        if (DEBUG_SHADER_ERRORS) {
            std::string typeStr;

            if (type == GL_VERTEX_SHADER) {
                typeStr = "vertex shader";
            } else if (type == GL_FRAGMENT_SHADER) {
                typeStr = "fragment shader";
            }

            printf("shader compilation error: %s\ntype: %s\n", messages, typeStr.c_str());
        }

        error = std::string(messages);
    }

    return handle;
}

/**
 * Destroy the shader.
 *
 * Note: has to be called in OpenGL thread.
 */
void AnyShader::destroy() {
    if (prog != INVALID_PROGRAM) {
        glDeleteProgram(prog);
        prog = INVALID_PROGRAM;
    }

    //reset failed
    failed = false;
}

/**
 * Get attribute location.
 */
GLint AnyShader::getAttributeLocation(std::string name) {
    GLint loc = glGetAttribLocation(prog, name.c_str());

    if (DEBUG_SHADER_ERRORS) {
        if (loc == -1) {
            printf("could not get location of attribute %s\n", name.c_str());
        }
    }

    return loc;
}

/**
 * Get uniform location.
 */
GLint AnyShader::getUniformLocation(std::string name) {
    GLint loc = glGetUniformLocation(prog, name.c_str());

    if (DEBUG_SHADER_ERRORS) {
        if (loc == -1) {
            printf("could not get location of uniform %s\n", name.c_str());
        }
    }

    return loc;
}

/**
 * Use the shader.
 *
 * Note: has to be called before any setters are used!
 */
void AnyShader::useShader(bool active) {
    if (!active) {
        glUseProgram(prog);
    }
}

//
// AnyAminoShader
//

AnyAminoShader::AnyAminoShader() : AnyShader() {
    //default vertex shader
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        attribute vec4 pos;

        void main() {
            gl_Position = mvp * trans * pos;
        }
    )";
}

/**
 * Initialize the shader.
 */
void AnyAminoShader::initShader() {
    useShader(false);

    //attributes
    aPos = getAttributeLocation("pos");

    //uniforms
    uMVP = getUniformLocation("mvp");
    uTrans = getUniformLocation("trans");
}

/**
 * Set transformation matrix.
 */
void AnyAminoShader::setTransformation(GLfloat modelView[16], GLfloat transition[16]) {
    glUniformMatrix4fv(uMVP, 1, GL_FALSE, modelView);
    glUniformMatrix4fv(uTrans, 1, GL_FALSE, transition);
}

/**
 * Set vertex data.
 */
void AnyAminoShader::setVertexData(GLsizei dim, GLfloat *vertices) {
    /*
     * Coords per vertex (2 or 3).
     *
     * Note: vertices is NULL in case of VBO usage
     */

    glVertexAttribPointer(aPos, dim, GL_FLOAT, GL_FALSE, 0, vertices);
}

/**
 * Draw triangles.
 */
void AnyAminoShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aPos);

    glDrawArrays(mode, 0, vertices);

    glDisableVertexAttribArray(aPos);
}

/**
 * Draw elements.
 */
void AnyAminoShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aPos);

    //Note: indices is offset in case of VBO
    glDrawElements(mode, elements, GL_UNSIGNED_SHORT, indices);

    glDisableVertexAttribArray(aPos);
}

//
// ColorShader
//

/**
 * Create color shader.
 */
ColorShader::ColorShader() : AnyAminoShader() {
    //shaders
    fragmentShader = R"(
        uniform vec4 color;

        void main() {
            gl_FragColor = color;
        }
    )";
}

/**
 * Initialize the color shader.
 */
void ColorShader::initShader() {
    AnyAminoShader::initShader();

    //uniforms
    uColor = getUniformLocation("color");
}

/**
 * Set color.
 */
void ColorShader::setColor(GLfloat color[4]) {
    glUniform4f(uColor, color[0], color[1], color[2], color[3]);
}

//
// ColorLightingShader
//

/**
 * Create color lighting shader.
 */
ColorLightingShader::ColorLightingShader() : ColorShader() {
    //shaders
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        //uniform mat4 normalMatrix;
        uniform vec3 lightDir;

        attribute vec4 pos;
        attribute vec3 normal;

        varying float lightFac;

        void main() {
            gl_Position = mvp * trans * pos;

            //simple version
            vec4 normalTrans = trans * vec4(normal, 0.);

            lightFac = abs(dot(normalTrans.xyz, -lightDir));
        }
    )";

    fragmentShader = R"(
        varying float lightFac;

        uniform vec4 color;

        void main() {
            gl_FragColor = vec4(color.rgb * lightFac, color.a);
        }
    )";
}

/**
 * Initialize the color lighting shader.
 */
void ColorLightingShader::initShader() {
    ColorShader::initShader();

    //attributes
    aNormal = getAttributeLocation("normal");

    //uniforms
    //uNormalMatrix = getUniformLocation("normalMatrix");
    uLightDir = getUniformLocation("lightDir");

    //default values
    GLfloat lightDir[3] = { 0, 0, -1 }; //parallel light on screen

    setLightDirection(lightDir);
}

/**
 * Set light direction.
 */
void ColorLightingShader::setLightDirection(GLfloat dir[3]) {
    glUniform3f(uLightDir, dir[0], dir[1], dir[2]);
}

/**
 * Set normal vectors.
 */
void ColorLightingShader::setNormalVectors(GLfloat *normals) {
    glVertexAttribPointer(aNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
}

/**
 * Set matrix.
 */
void ColorLightingShader::setTransformation(GLfloat modelView[16], GLfloat transition[16]) {
    AnyAminoShader::setTransformation(modelView, transition);

    //normal matrix
    /*
    GLfloat invMatrix[16];
    GLfloat normalMatrix[16];

    assert(invert_matrix(transition, invMatrix));
    transpose_matrix(normalMatrix, invMatrix);

    glUniformMatrix4fv(uNormalMatrix, 1, GL_FALSE, normalMatrix);
    */
}

/**
 * Draw triangles.
 */
void ColorLightingShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    AnyAminoShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aNormal);
}

/**
 * Draw elements.
 */
void ColorLightingShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    AnyAminoShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aNormal);
}

//
// TextureShader
//

TextureShader::TextureShader() : AnyAminoShader() {
    //shader
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        attribute vec4 pos;
        attribute vec2 texCoord;

        varying vec2 uv;

        void main() {
            gl_Position = mvp * trans * pos;
            uv = texCoord;
        }
    )";

    fragmentShader = R"(
        varying vec2 uv;

        uniform float opacity;
        uniform sampler2D tex;

        void main() {
            vec4 pixel = texture2D(tex, uv);

            gl_FragColor = vec4(pixel.rgb, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the color shader.
 */
void TextureShader::initShader() {
    AnyAminoShader::initShader();

    //attributes
    aTexCoord = getAttributeLocation("texCoord");

    //uniforms
    uOpacity = getUniformLocation("opacity");
    uTex = getUniformLocation("tex");

    //default values
    glUniform1i(uTex, 0); //GL_TEXTURE0
}

/**
 * Set opacity.
 */
void TextureShader::setOpacity(GLfloat opacity) {
    glUniform1f(uOpacity, opacity);
}

/**
 * Set texture coordinates.
 */
void TextureShader::setTextureCoordinates(GLfloat uv[][2]) {
    glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 0, uv);
}

/**
 * Draw texture.
 */
void TextureShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aTexCoord);

    glActiveTexture(GL_TEXTURE0);

    AnyAminoShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aTexCoord);
}

/**
 * Draw elements.
 */
void TextureShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aTexCoord);

    glActiveTexture(GL_TEXTURE0);

    AnyAminoShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aTexCoord);
}

//
// TextureClampToBorderShader
//

TextureClampToBorderShader::TextureClampToBorderShader() : TextureShader() {
    //Note: supports clamp to border, using transparent texture
    fragmentShader = R"(
        varying vec2 uv;

        uniform float opacity;
        uniform sampler2D tex;

        float clamp_to_border_factor(vec2 coords) {
            bvec2 out1 = greaterThan(coords, vec2(1, 1));
            bvec2 out2 = lessThan(coords, vec2(0, 0));
            bool do_clamp = (any(out1) || any(out2));

            return float(!do_clamp);
        }

        void main() {
            vec4 pixel = texture2D(tex, uv);

            gl_FragColor = vec4(pixel.rgb, pixel.a * opacity * clamp_to_border_factor(uv));
        }
    )";
}

//
// TextureLightingShader
//

/**
 * Create color lighting shader.
 */
TextureLightingShader::TextureLightingShader() : TextureShader() {
    //shaders
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        uniform vec3 lightDir;

        attribute vec4 pos;
        attribute vec2 texCoord;
        attribute vec3 normal;

        varying vec2 uv;
        varying float lightFac;

        void main() {
            gl_Position = mvp * trans * pos;

            uv = texCoord;

            vec4 normalTrans = trans * vec4(normal, 0.);

            //translucent layers
            lightFac = abs(dot(normalTrans.xyz, -lightDir));
        }
    )";

    fragmentShader = R"(
        varying vec2 uv;
        varying float lightFac;

        uniform float opacity;
        uniform sampler2D tex;

        void main() {
            vec4 pixel = texture2D(tex, uv);

            gl_FragColor = vec4(pixel.rgb * lightFac, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the color lighting shader.
 */
void TextureLightingShader::initShader() {
    TextureShader::initShader();

    //attributes
    aNormal = getAttributeLocation("normal");

    //uniforms
    //uNormalMatrix = getUniformLocation("normalMatrix");
    uLightDir = getUniformLocation("lightDir");

    //default values
    GLfloat lightDir[3] = { 0, 0, -1 }; //parallel light on screen

    setLightDirection(lightDir);
}

/**
 * Set light direction.
 */
void TextureLightingShader::setLightDirection(GLfloat dir[3]) {
    glUniform3f(uLightDir, dir[0], dir[1], dir[2]);
}

/**
 * Set normal vectors.
 */
void TextureLightingShader::setNormalVectors(GLfloat *normals) {
    glVertexAttribPointer(aNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
}

/**
 * Draw triangles.
 */
void TextureLightingShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    TextureShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aNormal);
}

/**
 * Draw elements.
 */
void TextureLightingShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    TextureShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aNormal);
}
<|endoftext|>


<commit_before>#include <iostream>
#include "unittest.hxx"

#include "vigra/accessor.hxx"
#include "vigra/tinyvector.hxx"
#include "vigra/rgbvalue.hxx"

using namespace vigra;

static float di[] = {1, 2, 4 };
static float df[] = {1.2, 2.4, 3.6 };

template <class BVector, class IVector, class FVector>
struct TinyVectorTest
{
    typedef BVector BV;
    typedef IVector IV;
    typedef FVector FV;

    BV bv0, bv1, bv3;
    IV iv0, iv1, iv3;
    FV fv0, fv1, fv3;

    template <class VECTOR>
    void printVector(VECTOR const & v)
    {
        std::cerr << "(";
        for(int i=0; i<v.size(); ++i)
            std::cerr << (float)v[i] << ", ";
        std::cerr << ")\n";
    }

    template <class VECTOR, class VALUE>
    bool equalValue(VECTOR const & v, VALUE const & vv)
    {
        for(int i=0; i<v.size(); ++i)
            if(v[i] != vv)
                return false;
        return true;
    }

    template <class VECTOR1, class VECTOR2>
    bool equalVector(VECTOR1 const & v1, VECTOR2 const & v2)
    {
        for(int i=0; i<v1.size(); ++i)
            if(v1[i] != v2[i])
                return false;
        return true;
    }

    template <class ITER1, class ITER2>
    bool equalIter(ITER1 i1, ITER1 i1end, ITER2 i2)
    {
        if(i1end - i1 != 3)
            return false;
        for(; i1<i1end; ++i1, ++i2)
            if(*i1 != *i2)
                return false;
        return true;
    }

    TinyVectorTest()
    : bv0(0), bv1(1), bv3(),
      iv0(0), iv1(1), iv3(),
      fv0(0.0), fv1(1.0), fv3()
    {
        bv3.init(df, df+3);
        iv3.init(df, df+3);
        fv3.init(df, df+3);
    }

    void testConstruction()
    {
        should(bv0.size() == 3);
        should(iv0.size() == 3);
        should(fv0.size() == 3);

        should(equalValue(bv0, 0));
        should(equalValue(iv0, 0));
        should(equalValue(fv0, 0.0f));

        should(equalValue(bv1, 1));
        should(equalValue(iv1, 1));
        should(equalValue(fv1, 1.0f));

        should(equalIter(bv3.begin(), bv3.end(), di));
        should(equalIter(iv3.begin(), iv3.end(), di));
        should(equalIter(fv3.begin(), fv3.end(), df));

        should(!equalVector(bv3, fv3));
        should(!equalVector(iv3, fv3));

        BV bv(fv3);
        should(equalIter(bv3.begin(), bv3.end(), bv.begin()));
        should(equalVector(bv3, bv));

        FV fv(iv3);
        should(equalIter(iv3.begin(), iv3.end(), fv.begin()));
        should(equalVector(iv3, fv));

        fv = fv3;
        should(equalIter(fv3.begin(), fv3.end(), fv.begin()));
        should(equalVector(fv3, fv));

        fv = bv3;
        should(equalIter(bv3.begin(), bv3.end(), fv.begin()));
        should(equalVector(bv3, fv));
    }

    void testComparison()
    {
        should(bv0 == bv0);
        should(iv0 == iv0);
        should(fv0 == fv0);
        should(iv0 == bv0);
        should(iv0 == fv0);
        should(fv0 == bv0);

        should(bv3 == bv3);
        should(iv3 == iv3);
        should(fv3 == fv3);
        should(iv3 == bv3);
        should(iv3 != fv3);
        should(fv3 != bv3);
    }

    void testArithmetic()
    {
        IV ivm3 = -iv3;
        FV fvm3 = -fv3;

        int mi[] = { -1, -2, -4};
        float mf[] = { -1.2, -2.4, -3.6 };

        should(equalIter(ivm3.begin(), ivm3.end(), mi));
        should(equalIter(fvm3.begin(), fvm3.end(), mf));

        IV iva3 = abs(ivm3);
        FV fva3 = abs(fvm3);
        should(equalVector(iv3, iva3));
        should(equalVector(fv3, fva3));

        int fmi[] = { -2, -3, -4};
        int fpi[] = { 1, 2, 3};
        IV ivi3 = floor(fvm3);
        should(equalIter(ivi3.begin(), ivi3.end(), fmi));
        ivi3 = -ceil(fv3);
        should(equalIter(ivi3.begin(), ivi3.end(), fmi));
        ivi3 = floor(fv3);
        should(equalIter(ivi3.begin(), ivi3.end(), fpi));
        ivi3 = -ceil(fvm3);
        should(equalIter(ivi3.begin(), ivi3.end(), fpi));

        should(bv1.squaredMagnitude() == 3);
        should(iv1.squaredMagnitude() == 3);
        should(fv1.squaredMagnitude() == 3.0);

        shouldEqualTolerance(fv3.squaredMagnitude(), (1.2f*1.2f + 2.4f*2.4f + 3.6f*3.6f), 1e-7f);

        should(dot(bv3, bv3) == bv3.squaredMagnitude());
        should(dot(iv3, bv3) == iv3.squaredMagnitude());
        should(dot(fv3, fv3) == fv3.squaredMagnitude());

        should(sqrt(dot(bv3, bv3)) == bv3.magnitude());
        should(sqrt(dot(iv3, bv3)) == iv3.magnitude());
        should(sqrt(dot(fv3, fv3)) == fv3.magnitude());

        BV bv = bv3;
        bv[2] = 200;
        should(dot(bv, bv) == 40005);
        should(bv.squaredMagnitude() == 40005);

        should(equalVector(bv3 - iv3, bv0));
        should(equalVector(fv3 - fv3, fv0));
        BV bvp = (bv3 + bv3)*0.5;
        FV fvp = (fv3 + fv3)*0.5;
        should(equalVector(bvp, bv3));
        should(equalVector(fvp, fv3));
        bvp = 2.0*bv3 - bv3;
        fvp = 2.0*fv3 - fv3;
        should(equalVector(bvp, bv3));
        should(equalVector(fvp, fv3));

        IV ivp = bv + bv;
        int ip1[] = {2, 4, 400};
        should(equalIter(ivp.begin(), ivp.end(), ip1));
        should(equalVector(bv0 - iv1, -iv1));

        bvp = bv3 / 2.0;
        fvp = bv3 / 2.0;
        int ip[] = {1, 1, 2};
        float fp[] = {0.5, 1.0, 2.0};
        should(equalIter(bvp.begin(), bvp.end(), ip));
        should(equalIter(fvp.begin(), fvp.end(), fp));
        fvp = fv3 / 2.0;
        float fp1[] = {0.6, 1.2, 1.8};
        should(equalIter(fvp.begin(), fvp.end(), fp1));
    }

    void testAccessor()
    {
        vigra::VectorAccessor<FV> v;
        FV  pfa[] = {fv3, fv1};
        FV * pf = pfa;

        should(v.size(pf) == 3);
        should(v.size(pf, 1) == 3);
        should(equalVector(v(pf), fv3));
        should(equalIter(v.begin(pf), v.end(pf), fv3.begin()));
        should(v.getComponent(pf, 2) == fv3[2]);
        v.setComponent(5.5, pf, 1);
        should(pf[0][1] == 5.5);
        should(equalVector(v(pf, 1), fv1));
        should(equalIter(v.begin(pf, 1), v.end(pf, 1), fv1.begin()));
        should(v.getComponent(pf, 1, 2) == fv1[2]);
        v.setComponent(5.5, pf, 1, 1);
        should(pf[1][1] == 5.5);
    }
};

struct RGBValueTest
: public TinyVectorTest<vigra::RGBValue<unsigned char>,
                        vigra::RGBValue<int>,
                        vigra::RGBValue<float> >
{
    typedef TinyVectorTest<vigra::RGBValue<unsigned char>,
                           vigra::RGBValue<int>,
                           vigra::RGBValue<float> > Base;

    RGBValueTest()
    : Base()
    {}

    void testRGBAccessors()
    {
        vigra::RGBAccessor<FV> rgb;
        vigra::RedAccessor<FV> red;
        vigra::GreenAccessor<FV> green;
        vigra::BlueAccessor<FV> blue;
        vigra::RGBToGrayAccessor<FV> gray;

        FV pfa[] = { FV(0.0), FV(1.0)};
        FV * pf = pfa;

        should(rgb(pf) == vigra::NumericTraits<FV>::zero());
        should(red(pf) == 0.0);
        should(green(pf) == 0.0);
        should(blue(pf) == 0.0);
        should(gray(pf) == 0.0);

        should(rgb(pf, 1) == vigra::NumericTraits<FV>::one());
        should(red(pf, 1) == 1.0);
        should(green(pf, 1) == 1.0);
        should(blue(pf, 1) == 1.0);
        should(gray(pf, 1) == 1.0);

        rgb.setRed(1.0, pf);
        rgb.setGreen(2.0, pf);
        rgb.setBlue(3.0, pf);
        should(red(pf) == 1.0);
        should(green(pf) == 2.0);
        should(blue(pf) == 3.0);

        red.set(4.0, pf);
        green.set(5.0, pf);
        blue.set(6.0, pf);
        should(rgb.red(pf) == 4.0);
        should(rgb.green(pf) == 5.0);
        should(rgb.blue(pf) == 6.0);
        should(vigra::abs(gray(pf) - 4.81) < 0.00001);

        rgb.setRed(7.0, pf, 1);
        rgb.setGreen(8.0, pf, 1);
        rgb.setBlue(9.0, pf, 1);
        should(red(pf, 1) == 7.0);
        should(green(pf, 1) == 8.0);
        should(blue(pf, 1) == 9.0);

        red.set(10.0, pf, 1);
        green.set(11.0, pf, 1);
        blue.set(12.0, pf, 1);
        should(rgb.red(pf, 1) == 10.0);
        should(rgb.green(pf, 1) == 11.0);
        should(rgb.blue(pf, 1) == 12.0);
        should(vigra::abs(gray(pf, 1) - 10.81) <0.00001);
    }

};

struct PixelTypesTestSuite
: public vigra::test_suite
{
    typedef TinyVectorTest<vigra::TinyVector<unsigned char, 3>,
                           vigra::TinyVector<int, 3>,
                           vigra::TinyVector<float, 3> > TinyVectorTest;

    PixelTypesTestSuite()
    : vigra::test_suite("PixelTypesTest")
    {
        add( testCase(&TinyVectorTest::testConstruction));
        add( testCase(&TinyVectorTest::testComparison));
        add( testCase(&TinyVectorTest::testArithmetic));
        add( testCase(&TinyVectorTest::testAccessor));

        add( testCase(&RGBValueTest::testConstruction));
        add( testCase(&RGBValueTest::testComparison));
        add( testCase(&RGBValueTest::testArithmetic));
        add( testCase(&RGBValueTest::testAccessor));
        add( testCase(&RGBValueTest::testRGBAccessors));
    }
};

int main()
{
    PixelTypesTestSuite test;

    int failed = test.run();

    std::cout << test.report() << std::endl;

    return (failed != 0);
}
<commit_msg>added typecasts necessary for g++ 3<commit_after>#include <iostream>
#include "unittest.hxx"

#include "vigra/accessor.hxx"
#include "vigra/tinyvector.hxx"
#include "vigra/rgbvalue.hxx"

using namespace vigra;

static float di[] = {1, 2, 4 };
static float df[] = {1.2, 2.4, 3.6 };

template <class BVector, class IVector, class FVector>
struct TinyVectorTest
{
    typedef BVector BV;
    typedef IVector IV;
    typedef FVector FV;

    BV bv0, bv1, bv3;
    IV iv0, iv1, iv3;
    FV fv0, fv1, fv3;

    template <class VECTOR>
    void printVector(VECTOR const & v)
    {
        std::cerr << "(";
        for(int i=0; i<v.size(); ++i)
            std::cerr << (float)v[i] << ", ";
        std::cerr << ")\n";
    }

    template <class VECTOR, class VALUE>
    bool equalValue(VECTOR const & v, VALUE const & vv)
    {
        for(int i=0; i<v.size(); ++i)
            if(v[i] != vv)
                return false;
        return true;
    }

    template <class VECTOR1, class VECTOR2>
    bool equalVector(VECTOR1 const & v1, VECTOR2 const & v2)
    {
        for(int i=0; i<v1.size(); ++i)
            if(v1[i] != v2[i])
                return false;
        return true;
    }

    template <class ITER1, class ITER2>
    bool equalIter(ITER1 i1, ITER1 i1end, ITER2 i2)
    {
        if(i1end - i1 != 3)
            return false;
        for(; i1<i1end; ++i1, ++i2)
            if(*i1 != *i2)
                return false;
        return true;
    }

    TinyVectorTest()
    : bv0(0), bv1(1), bv3(),
      iv0(0), iv1(1), iv3(),
      fv0(0.0), fv1(1.0), fv3()
    {
        bv3.init(df, df+3);
        iv3.init(df, df+3);
        fv3.init(df, df+3);
    }

    void testConstruction()
    {
        should(bv0.size() == 3);
        should(iv0.size() == 3);
        should(fv0.size() == 3);

        should(equalValue(bv0, 0));
        should(equalValue(iv0, 0));
        should(equalValue(fv0, 0.0f));

        should(equalValue(bv1, 1));
        should(equalValue(iv1, 1));
        should(equalValue(fv1, 1.0f));

        should(equalIter(bv3.begin(), bv3.end(), di));
        should(equalIter(iv3.begin(), iv3.end(), di));
        should(equalIter(fv3.begin(), fv3.end(), df));

        should(!equalVector(bv3, fv3));
        should(!equalVector(iv3, fv3));

        BV bv(fv3);
        should(equalIter(bv3.begin(), bv3.end(), bv.begin()));
        should(equalVector(bv3, bv));

        FV fv(iv3);
        should(equalIter(iv3.begin(), iv3.end(), fv.begin()));
        should(equalVector(iv3, fv));

        fv = fv3;
        should(equalIter(fv3.begin(), fv3.end(), fv.begin()));
        should(equalVector(fv3, fv));

        fv = bv3;
        should(equalIter(bv3.begin(), bv3.end(), fv.begin()));
        should(equalVector(bv3, fv));
    }

    void testComparison()
    {
        should(bv0 == bv0);
        should(iv0 == iv0);
        should(fv0 == fv0);
        should(iv0 == bv0);
        should(iv0 == fv0);
        should(fv0 == bv0);

        should(bv3 == bv3);
        should(iv3 == iv3);
        should(fv3 == fv3);
        should(iv3 == bv3);
        should(iv3 != fv3);
        should(fv3 != bv3);
    }

    void testArithmetic()
    {
        IV ivm3 = -iv3;
        FV fvm3 = -fv3;

        int mi[] = { -1, -2, -4};
        float mf[] = { -1.2, -2.4, -3.6 };

        should(equalIter(ivm3.begin(), ivm3.end(), mi));
        should(equalIter(fvm3.begin(), fvm3.end(), mf));

        IV iva3 = abs(ivm3);
        FV fva3 = abs(fvm3);
        should(equalVector(iv3, iva3));
        should(equalVector(fv3, fva3));

        int fmi[] = { -2, -3, -4};
        int fpi[] = { 1, 2, 3};
        IV ivi3 = floor(fvm3);
        should(equalIter(ivi3.begin(), ivi3.end(), fmi));
        ivi3 = -ceil(fv3);
        should(equalIter(ivi3.begin(), ivi3.end(), fmi));
        ivi3 = floor(fv3);
        should(equalIter(ivi3.begin(), ivi3.end(), fpi));
        ivi3 = -ceil(fvm3);
        should(equalIter(ivi3.begin(), ivi3.end(), fpi));

        should(bv1.squaredMagnitude() == 3);
        should(iv1.squaredMagnitude() == 3);
        should(fv1.squaredMagnitude() == 3.0);

        shouldEqualTolerance(fv3.squaredMagnitude(), (1.2f*1.2f + 2.4f*2.4f + 3.6f*3.6f), 1e-7f);

        should(dot(bv3, bv3) == bv3.squaredMagnitude());
        should(dot(iv3, bv3) == iv3.squaredMagnitude());
        should(dot(fv3, fv3) == fv3.squaredMagnitude());

        shouldEqualTolerance(VIGRA_CSTD::sqrt(
                (NumericTraits<typename BV::value_type>::RealPromote)
                dot(bv3, bv3)), bv3.magnitude(), 0.0);
        shouldEqualTolerance(VIGRA_CSTD::sqrt(
                (NumericTraits<typename IV::value_type>::RealPromote)
                dot(iv3, bv3)), iv3.magnitude(), 0.0);
        shouldEqualTolerance(VIGRA_CSTD::sqrt(
                (NumericTraits<typename FV::value_type>::RealPromote)
                dot(fv3, fv3)), fv3.magnitude(), 0.0);

        BV bv = bv3;
        bv[2] = 200;
        should(dot(bv, bv) == 40005);
        should(bv.squaredMagnitude() == 40005);

        should(equalVector(bv3 - iv3, bv0));
        should(equalVector(fv3 - fv3, fv0));
        BV bvp = (bv3 + bv3)*0.5;
        FV fvp = (fv3 + fv3)*0.5;
        should(equalVector(bvp, bv3));
        should(equalVector(fvp, fv3));
        bvp = 2.0*bv3 - bv3;
        fvp = 2.0*fv3 - fv3;
        should(equalVector(bvp, bv3));
        should(equalVector(fvp, fv3));

        IV ivp = bv + bv;
        int ip1[] = {2, 4, 400};
        should(equalIter(ivp.begin(), ivp.end(), ip1));
        should(equalVector(bv0 - iv1, -iv1));

        bvp = bv3 / 2.0;
        fvp = bv3 / 2.0;
        int ip[] = {1, 1, 2};
        float fp[] = {0.5, 1.0, 2.0};
        should(equalIter(bvp.begin(), bvp.end(), ip));
        should(equalIter(fvp.begin(), fvp.end(), fp));
        fvp = fv3 / 2.0;
        float fp1[] = {0.6, 1.2, 1.8};
        should(equalIter(fvp.begin(), fvp.end(), fp1));
    }

    void testAccessor()
    {
        vigra::VectorAccessor<FV> v;
        FV  pfa[] = {fv3, fv1};
        FV * pf = pfa;

        should(v.size(pf) == 3);
        should(v.size(pf, 1) == 3);
        should(equalVector(v(pf), fv3));
        should(equalIter(v.begin(pf), v.end(pf), fv3.begin()));
        should(v.getComponent(pf, 2) == fv3[2]);
        v.setComponent(5.5, pf, 1);
        should(pf[0][1] == 5.5);
        should(equalVector(v(pf, 1), fv1));
        should(equalIter(v.begin(pf, 1), v.end(pf, 1), fv1.begin()));
        should(v.getComponent(pf, 1, 2) == fv1[2]);
        v.setComponent(5.5, pf, 1, 1);
        should(pf[1][1] == 5.5);
    }
};

struct RGBValueTest
: public TinyVectorTest<vigra::RGBValue<unsigned char>,
                        vigra::RGBValue<int>,
                        vigra::RGBValue<float> >
{
    typedef TinyVectorTest<vigra::RGBValue<unsigned char>,
                           vigra::RGBValue<int>,
                           vigra::RGBValue<float> > Base;

    RGBValueTest()
    : Base()
    {}

    void testRGBAccessors()
    {
        vigra::RGBAccessor<FV> rgb;
        vigra::RedAccessor<FV> red;
        vigra::GreenAccessor<FV> green;
        vigra::BlueAccessor<FV> blue;
        vigra::RGBToGrayAccessor<FV> gray;

        FV pfa[] = { FV(0.0), FV(1.0)};
        FV * pf = pfa;

        should(rgb(pf) == vigra::NumericTraits<FV>::zero());
        should(red(pf) == 0.0);
        should(green(pf) == 0.0);
        should(blue(pf) == 0.0);
        should(gray(pf) == 0.0);

        should(rgb(pf, 1) == vigra::NumericTraits<FV>::one());
        should(red(pf, 1) == 1.0);
        should(green(pf, 1) == 1.0);
        should(blue(pf, 1) == 1.0);
        should(gray(pf, 1) == 1.0);

        rgb.setRed(1.0, pf);
        rgb.setGreen(2.0, pf);
        rgb.setBlue(3.0, pf);
        should(red(pf) == 1.0);
        should(green(pf) == 2.0);
        should(blue(pf) == 3.0);

        red.set(4.0, pf);
        green.set(5.0, pf);
        blue.set(6.0, pf);
        should(rgb.red(pf) == 4.0);
        should(rgb.green(pf) == 5.0);
        should(rgb.blue(pf) == 6.0);
        should(vigra::abs(gray(pf) - 4.81) < 0.00001);

        rgb.setRed(7.0, pf, 1);
        rgb.setGreen(8.0, pf, 1);
        rgb.setBlue(9.0, pf, 1);
        should(red(pf, 1) == 7.0);
        should(green(pf, 1) == 8.0);
        should(blue(pf, 1) == 9.0);

        red.set(10.0, pf, 1);
        green.set(11.0, pf, 1);
        blue.set(12.0, pf, 1);
        should(rgb.red(pf, 1) == 10.0);
        should(rgb.green(pf, 1) == 11.0);
        should(rgb.blue(pf, 1) == 12.0);
        should(vigra::abs(gray(pf, 1) - 10.81) <0.00001);
    }

};

struct PixelTypesTestSuite
: public vigra::test_suite
{
    typedef TinyVectorTest<vigra::TinyVector<unsigned char, 3>,
                           vigra::TinyVector<int, 3>,
                           vigra::TinyVector<float, 3> > TinyVectorTest;

    PixelTypesTestSuite()
    : vigra::test_suite("PixelTypesTest")
    {
        add( testCase(&TinyVectorTest::testConstruction));
        add( testCase(&TinyVectorTest::testComparison));
        add( testCase(&TinyVectorTest::testArithmetic));
        add( testCase(&TinyVectorTest::testAccessor));

        add( testCase(&RGBValueTest::testConstruction));
        add( testCase(&RGBValueTest::testComparison));
        add( testCase(&RGBValueTest::testArithmetic));
        add( testCase(&RGBValueTest::testAccessor));
        add( testCase(&RGBValueTest::testRGBAccessors));
    }
};

int main()
{
    PixelTypesTestSuite test;

    int failed = test.run();

    std::cout << test.report() << std::endl;

    return (failed != 0);
}
<|endoftext|>


<commit_before>//
//  ThreadUtils.hpp
//  Pods
//
//  Created by eps on 6/16/20.
//

#ifndef EE_X_THREAD_UTILS_HPP
#define EE_X_THREAD_UTILS_HPP

#ifdef __cplusplus

#include <future>

#include "ee/CoreFwd.hpp"

namespace ee {
namespace core {
template <class T = void>
using Runnable = std::function<T()>;

class Thread {
public:
    /// Checks whether the current thread is the UI thread (Android) or Main
    /// thread (iOS).
    static bool isMainThread();

    /// Runs the specified runnable on the main thread.
    /// @returns Whether the function is executed immediately.
    static bool runOnMainThread(const Runnable<>& runnable);

    /// Runs the specifieid runnable on the main thread after a delay.
    static void runOnMainThreadDelayed(const Runnable<>& runnable, float delay);
};

/// Runs the specified runnable on the main thread and block the current
/// thread. If the current thread is the main thread, it will be executed
/// immediately.
[[deprecated]] void runOnUiThreadAndWait(const Runnable<>& runnable);

template <class T>
[[deprecated]] T runOnUiThreadAndWaitResult(const Runnable<T>& runnable) {
    std::promise<T> promise;
    runOnUiThread([runnable, &promise] { // Fix clang-format.
        promise.set_value(runnable());
    });
    return promise.get_future().get();
}
} // namespace core

constexpr auto isMainThread = &Thread::isMainThread;
constexpr auto runOnMainThread = &Thread::runOnMainThread;
constexpr auto runOnMainThreadDelayed = &Thread::runOnMainThreadDelayed;
[[deprecated]] constexpr auto runOnUiThread = runOnMainThread;
[[deprecated]] constexpr auto runOnUiThreadDelayed = runOnMainThreadDelayed;
using core::runOnUiThreadAndWait;
using core::runOnUiThreadAndWaitResult;
} // namespace ee

#endif // __cplusplus

#if defined(EE_X_IOS) || defined(EE_X_OSX)
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

extern void ee_runOnMainThreadCallback();
extern void ee_runOnMainThreadDelayedCallback(int key);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // defined(EE_X_IOS) || defined(EE_X_OSX)

#endif /* EE_X_THREAD_UTILS_HPP */
<commit_msg>Rename header guard.<commit_after>//
//  ThreadUtils.hpp
//  Pods
//
//  Created by eps on 6/16/20.
//

#ifndef EE_X_THREAD_HPP
#define EE_X_THREAD_HPP

#ifdef __cplusplus

#include <future>

#include "ee/CoreFwd.hpp"

namespace ee {
namespace core {
template <class T = void>
using Runnable = std::function<T()>;

class Thread {
public:
    /// Checks whether the current thread is the UI thread (Android) or Main
    /// thread (iOS).
    static bool isMainThread();

    /// Runs the specified runnable on the main thread.
    /// @returns Whether the function is executed immediately.
    static bool runOnMainThread(const Runnable<>& runnable);

    /// Runs the specifieid runnable on the main thread after a delay.
    static void runOnMainThreadDelayed(const Runnable<>& runnable, float delay);
};

/// Runs the specified runnable on the main thread and block the current
/// thread. If the current thread is the main thread, it will be executed
/// immediately.
[[deprecated]] void runOnUiThreadAndWait(const Runnable<>& runnable);

template <class T>
[[deprecated]] T runOnUiThreadAndWaitResult(const Runnable<T>& runnable) {
    std::promise<T> promise;
    runOnUiThread([runnable, &promise] { // Fix clang-format.
        promise.set_value(runnable());
    });
    return promise.get_future().get();
}
} // namespace core

constexpr auto isMainThread = &Thread::isMainThread;
constexpr auto runOnMainThread = &Thread::runOnMainThread;
constexpr auto runOnMainThreadDelayed = &Thread::runOnMainThreadDelayed;
[[deprecated]] constexpr auto runOnUiThread = runOnMainThread;
[[deprecated]] constexpr auto runOnUiThreadDelayed = runOnMainThreadDelayed;
using core::runOnUiThreadAndWait;
using core::runOnUiThreadAndWaitResult;
} // namespace ee

#endif // __cplusplus

#if defined(EE_X_IOS) || defined(EE_X_OSX)
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

extern void ee_runOnMainThreadCallback();
extern void ee_runOnMainThreadDelayedCallback(int key);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // defined(EE_X_IOS) || defined(EE_X_OSX)

#endif /* EE_X_THREAD_HPP */
<|endoftext|>