<commit_before>//----------------------------------------------------------------------------
/// \file  time.hpp
//----------------------------------------------------------------------------
/// \brief Time-related functions
/// \author:  Serge Aleynikov
// Parts of code taken from:
// http://home.roadrunner.com/~hinnant/date_algorithms.html
//----------------------------------------------------------------------------
// Copyright (c) 2013-09-07 Howard Hinnant
// Created: 2003-07-10
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2014 Serge Aleynikov <saleyn@gmail.com>

This 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#pragma once

#include <utxx/compiler_hints.hpp>
#include <utxx/error.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#if __cplusplus >= 201103L
#  include <chrono>
#endif

namespace utxx {

    /// Returns true if y is a leap year
    inline bool is_leap(unsigned y) noexcept {
        unsigned  n =  y / 100, rem100 = y - n*100;
        bool rem400 = (n & 0x3) || rem100; // Is not divisible by 400
        return !rem400             // 1. The year divisible by 400 is always leap
            || (rem100 &&          // 2. The year divisible by 100 is not leap
               !(rem100 & 0x3));   // 3. The year divisible by 4   is leap
    }

    /// Returns number of days in a month (no range checking!)
    /// @param a_month        is a month number in range 1 to 12.
    /// @param a_is_leap_year indicates if this is a leap year
    inline unsigned days_in_a_month(unsigned a_month, bool a_is_leap_year) {
        assert(a_month >= 1 && a_month <= 12);
        static const unsigned s_ndays[2][12] = {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
        };
        return s_ndays[a_is_leap_year][a_month-1];
    }

    /// Returns number of days singe the beginning of year \a y.
    inline int days_since_beg_of_year(int y, int m, int d) noexcept {
        assert(m >= 1 && d <= 12);
        static const unsigned s_ndays[2][12] = {
            {0, 31, 31+28, 59+31, 90+30, 120+31, 151+30, 181+31, 212+31, 243+30, 273+31, 304+30},
            {0, 31, 31+29, 60+31, 91+30, 121+31, 152+30, 182+31, 213+31, 244+30, 274+31, 305+30}
        };
        int leap = is_leap(y);
        return s_ndays[leap][m-1] + d;
    }

    /// Return number of days between two y/m/d pairs.
    inline int date_diff(unsigned y1, unsigned m1, unsigned d1,
                         unsigned y2, unsigned m2, unsigned d2)
    {
        if (unlikely(m1 < 1 || m1 > 12 || m2 < 1 || m2 > 12))
            throw badarg_error("Invalid month value");

        auto days_since_year0 =
            [] (unsigned y) { return y*365 + y/400 + y/4 - y/100; };

        return days_since_year0(y2) - days_since_year0(y1)
            + days_since_beg_of_year(y2, m2, d2)
            - days_since_beg_of_year(y1, m1, d1);
    }

    /// Returns number of days since epoch 1970-01-01.
    /// Negative values indicate days prior to 1970-01-01.
    /// @param y represents a year in the Gregorian calendar
    ///          in range (numeric_limits<Int>::min()/366 to
    ///          numeric_limits<Int>::max()/366)
    /// @param m represents a month in the Gregorian calendar (1 to 12)
    /// @param d represents a day of month in the Gregorian calendar (1 ...)
    inline int to_gregorian_days(int y, unsigned m, unsigned d)
    {
        static_assert(std::numeric_limits<unsigned>::digits >= 18,
                "This algorithm has not been ported to a 16 bit unsigned integer");
        static_assert(std::numeric_limits<int>::digits >= 20,
                "This algorithm has not been ported to a 16 bit signed integer");
        if (utxx::unlikely(m < 1 || m > 12 || d < 1 || d > 31))
            throw badarg_error("Invalid range of month/day argument (m=",m, ", d=",d,')');

        const int yr  = y - (m <= 2);
        const int era = (yr >= 0 ? yr : yr-399) / 400;
        const unsigned yoe = static_cast<unsigned>(yr - era * 400);     // [0, 399]
        const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1;  // [0, 365]
        const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy;         // [0, 146096]
        return era * 146097 + int(doe) - 719468;
    }

    /// Returns year/month/day triple in Gregorian calendar.
    inline void from_gregorian_days(int a_days, int& y, unsigned& m, unsigned& d) noexcept
    {
        static_assert(std::numeric_limits<unsigned>::digits >= 18,
                "This algorithm has not been ported to a 16 bit unsigned integer");
        static_assert(std::numeric_limits<int>::digits >= 20,
                "This algorithm has not been ported to a 16 bit signed integer");
        const int     days = a_days + 719468;
        const int      era = (days >= 0 ? days : days - 146096) / 146097;
        const unsigned doe = static_cast<unsigned>(days - era * 146097);      // [0, 146096]
        const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
                         y = static_cast<int>(yoe) + era * 400;
        const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100);               // [0, 365]
        const unsigned  mp = (5*doy + 2)/153;                                 // [0, 11]
                         d = doy - (153*mp+2)/5 + 1;                          // [1, 31]
                         m = mp  + (mp < 10 ? 3 : -9);                        // [1, 12]
                         y = y   + (m <= 2);
    }

    /// Returns year/month/day triple in Gregorian calendar.
    /// @param a_days is number of days since 1970-01-01 and is in the range:
    ///     (numeric_limits<int>::min() to numeric_limits<int>::max()-719468).
    inline std::tuple<int, unsigned, unsigned> from_gregorian_days(int a_days) noexcept {
        int y; unsigned m, d;
        from_gregorian_days(a_days, y, m, d);
        return std::make_tuple(y, m, d);
    }

    /// Split seconds since epoch to y/m/d
    inline std::tuple<int, unsigned, unsigned>
    from_gregorian_time(time_t a_secs) noexcept {
        return from_gregorian_days(int(a_secs / 86400));
    }

    /// Split seconds since epoch to y/m/d
    inline void from_gregorian_time(time_t a_secs, int& y, unsigned& m, unsigned& d) noexcept {
        from_gregorian_days(int(a_secs / 86400), y, m, d);
    }

    template <class To, class Rep, class Period>
    To round_down(const std::chrono::duration<Rep, Period>& d) {
        To t = std::chrono::duration_cast<To>(d);
        return (t > d) ? t-1 : t;
    }

    /// Returns day of week in civil calendar [0, 6] -> [Sun, Sat].
    /// @param a_days is number of days since 1970-01-01 and is in the range:
    ///  [numeric_limits<Int>::min(), numeric_limits<Int>::max()-4].
    constexpr int weekday_from_days(int a_days) noexcept {
        return a_days >= -4 ? (a_days+4) % 7 : (a_days+5) % 7 + 6;
    }

    /// Returns day of week in civil calendar for y-m-d date. [0, 6] -> [Sun, Sat].
    constexpr int weekday(int y, int m, int d) {
		constexpr int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
		y -= m < 3;
		return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
	}

    /// Convert y/m/d into seconds since epoch 1970-1-1
    inline time_t mktime_utc(int y, unsigned m, unsigned d) {
        return to_gregorian_days(y, m, d) * 86400;
    }

    /// Convert date into seconds since epoch 1970-1-1
    inline time_t mktime_utc(int      year, unsigned month, unsigned day,
                             unsigned hour, unsigned min,   unsigned sec) {
        time_t res = to_gregorian_days(year, month, day) * 86400;
        res += 3600*hour + 60*min + sec;
        return res;
    }

    /// Convert tm structure into time since epoch 1970-1-1
    inline time_t mktime_utc(struct tm *tm) {
        return mktime_utc(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
                          tm->tm_hour, tm->tm_min, tm->tm_sec);
    }

#if __cplusplus >= 201103L

    // Example maketm_utc(std::chrono::system_clock::now())
    template <class Duration>
    std::tm
    to_tm_utc(std::chrono::time_point<std::chrono::system_clock, Duration> tp)
    {
        using period = std::ratio_multiply<
                        std::chrono::hours::period,
                        std::ratio<24>>;
        using days   = std::chrono::duration<int, period>;
        // t is time duration since 1970-01-01
        Duration t = tp.time_since_epoch();
        // d is days since 1970-01-01
        days d = round_down<days>(t);
        // t is now time duration since midnight of day d
        t -= d;
        // break d down into year/month/day
        int year, month, day;
        std::tie(year, month, day) = from_gregorian_days(d.count());

        int h  = std::chrono::duration_cast<std::chrono::hours>(t).count();
            t -= std::chrono::hours(tp);
        int m  = std::chrono::duration_cast<std::chrono::minutes>(t).count();
            t -= std::chrono::minutes(tp);
        int s  = std::chrono::duration_cast<std::chrono::seconds>(t).count();

        std::tm tm = {
            s, m, h, day, month-1, year-1900,
            weekday_from_days(d.count()), d.count() - to_gregorian_days(year,1,1),
            0, 0, 0
        };

        return tm;
    }

#endif

    //----------------------------------------------------------------------------
    /// Parse time in format "HH:MM[:SS][am|pm]" to seconds since midnight
    //----------------------------------------------------------------------------
    long parse_time_to_seconds(const char* a_tm, int a_sz = -1);

    //----------------------------------------------------------------------------
    /// Parse day of week "Sun" to "Sat" (case insensitive).
    /// Also accept "tod" and "today" for today's day.
    /// @param a_str       input string
    /// @param a_today_dow DOW of today, if known
    /// @param a_utc       use UTC timezone (only used when a_str is "tod[ay]" and
    ///                    \a a_today_dow is -1)
    /// @return 0-6 for Sun-Sat, or -1 for bad input. a_str is advanced to the end
    ///         of parsed input.
    //----------------------------------------------------------------------------
    int parse_dow_ref(const char*& a_str, int a_today_dow=-1, bool a_utc=false);

    inline int parse_dow(const char* a_str, int a_tod_dow=-1, bool a_utc=false) {
        return parse_dow_ref(a_str, a_tod_dow, a_utc);
    }

#ifdef _WIN32
    /// Simulated support of strptime(3) on Windows
    /// \see strptime(3)
    inline char* strptime(const char* str, const char* fmt, struct tm*  tm) {
        std::istringstream input(str);
        input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
        input >> std::get_time(tm, fmt);
        return input.fail() ? nullptr : (char*)(str + input.tellg());
    }
#endif

#endif
} // namespace utxx
<commit_msg>Update time.hpp<commit_after>//----------------------------------------------------------------------------
/// \file  time.hpp
//----------------------------------------------------------------------------
/// \brief Time-related functions
/// \author:  Serge Aleynikov
// Parts of code taken from:
// http://home.roadrunner.com/~hinnant/date_algorithms.html
//----------------------------------------------------------------------------
// Copyright (c) 2013-09-07 Howard Hinnant
// Created: 2003-07-10
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2014 Serge Aleynikov <saleyn@gmail.com>

This 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#pragma once

#include <utxx/compiler_hints.hpp>
#include <utxx/error.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#if __cplusplus >= 201103L
#  include <chrono>
#endif

namespace utxx {

    /// Returns true if y is a leap year
    inline bool is_leap(unsigned y) noexcept {
        unsigned  n =  y / 100, rem100 = y - n*100;
        bool rem400 = (n & 0x3) || rem100; // Is not divisible by 400
        return !rem400             // 1. The year divisible by 400 is always leap
            || (rem100 &&          // 2. The year divisible by 100 is not leap
               !(rem100 & 0x3));   // 3. The year divisible by 4   is leap
    }

    /// Returns number of days in a month (no range checking!)
    /// @param a_month        is a month number in range 1 to 12.
    /// @param a_is_leap_year indicates if this is a leap year
    inline unsigned days_in_a_month(unsigned a_month, bool a_is_leap_year) {
        assert(a_month >= 1 && a_month <= 12);
        static const unsigned s_ndays[2][12] = {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
        };
        return s_ndays[a_is_leap_year][a_month-1];
    }

    /// Returns number of days singe the beginning of year \a y.
    inline int days_since_beg_of_year(int y, int m, int d) noexcept {
        assert(m >= 1 && d <= 12);
        static const unsigned s_ndays[2][12] = {
            {0, 31, 31+28, 59+31, 90+30, 120+31, 151+30, 181+31, 212+31, 243+30, 273+31, 304+30},
            {0, 31, 31+29, 60+31, 91+30, 121+31, 152+30, 182+31, 213+31, 244+30, 274+31, 305+30}
        };
        int leap = is_leap(y);
        return s_ndays[leap][m-1] + d;
    }

    /// Return number of days between two y/m/d pairs.
    inline int date_diff(unsigned y1, unsigned m1, unsigned d1,
                         unsigned y2, unsigned m2, unsigned d2)
    {
        if (unlikely(m1 < 1 || m1 > 12 || m2 < 1 || m2 > 12))
            throw badarg_error("Invalid month value");

        auto days_since_year0 =
            [] (unsigned y) { return y*365 + y/400 + y/4 - y/100; };

        return days_since_year0(y2) - days_since_year0(y1)
            + days_since_beg_of_year(y2, m2, d2)
            - days_since_beg_of_year(y1, m1, d1);
    }

    /// Returns number of days since epoch 1970-01-01.
    /// Negative values indicate days prior to 1970-01-01.
    /// @param y represents a year in the Gregorian calendar
    ///          in range (numeric_limits<Int>::min()/366 to
    ///          numeric_limits<Int>::max()/366)
    /// @param m represents a month in the Gregorian calendar (1 to 12)
    /// @param d represents a day of month in the Gregorian calendar (1 ...)
    inline int to_gregorian_days(int y, unsigned m, unsigned d)
    {
        static_assert(std::numeric_limits<unsigned>::digits >= 18,
                "This algorithm has not been ported to a 16 bit unsigned integer");
        static_assert(std::numeric_limits<int>::digits >= 20,
                "This algorithm has not been ported to a 16 bit signed integer");
        if (utxx::unlikely(m < 1 || m > 12 || d < 1 || d > 31))
            throw badarg_error("Invalid range of month/day argument (m=",m, ", d=",d,')');

        const int yr  = y - (m <= 2);
        const int era = (yr >= 0 ? yr : yr-399) / 400;
        const unsigned yoe = static_cast<unsigned>(yr - era * 400);     // [0, 399]
        const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1;  // [0, 365]
        const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy;         // [0, 146096]
        return era * 146097 + int(doe) - 719468;
    }

    /// Returns year/month/day triple in Gregorian calendar.
    inline void from_gregorian_days(int a_days, int& y, unsigned& m, unsigned& d) noexcept
    {
        static_assert(std::numeric_limits<unsigned>::digits >= 18,
                "This algorithm has not been ported to a 16 bit unsigned integer");
        static_assert(std::numeric_limits<int>::digits >= 20,
                "This algorithm has not been ported to a 16 bit signed integer");
        const int     days = a_days + 719468;
        const int      era = (days >= 0 ? days : days - 146096) / 146097;
        const unsigned doe = static_cast<unsigned>(days - era * 146097);      // [0, 146096]
        const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
                         y = static_cast<int>(yoe) + era * 400;
        const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100);               // [0, 365]
        const unsigned  mp = (5*doy + 2)/153;                                 // [0, 11]
                         d = doy - (153*mp+2)/5 + 1;                          // [1, 31]
                         m = mp  + (mp < 10 ? 3 : -9);                        // [1, 12]
                         y = y   + (m <= 2);
    }

    /// Returns year/month/day triple in Gregorian calendar.
    /// @param a_days is number of days since 1970-01-01 and is in the range:
    ///     (numeric_limits<int>::min() to numeric_limits<int>::max()-719468).
    inline std::tuple<int, unsigned, unsigned> from_gregorian_days(int a_days) noexcept {
        int y; unsigned m, d;
        from_gregorian_days(a_days, y, m, d);
        return std::make_tuple(y, m, d);
    }

    /// Split seconds since epoch to y/m/d
    inline std::tuple<int, unsigned, unsigned>
    from_gregorian_time(time_t a_secs) noexcept {
        return from_gregorian_days(int(a_secs / 86400));
    }

    /// Split seconds since epoch to y/m/d
    inline void from_gregorian_time(time_t a_secs, int& y, unsigned& m, unsigned& d) noexcept {
        from_gregorian_days(int(a_secs / 86400), y, m, d);
    }

    template <class To, class Rep, class Period>
    To round_down(const std::chrono::duration<Rep, Period>& d) {
        To t = std::chrono::duration_cast<To>(d);
        return (t > d) ? t-1 : t;
    }

    /// Returns day of week in civil calendar [0, 6] -> [Sun, Sat].
    /// @param a_days is number of days since 1970-01-01 and is in the range:
    ///  [numeric_limits<Int>::min(), numeric_limits<Int>::max()-4].
    constexpr int weekday_from_days(int a_days) noexcept {
        return a_days >= -4 ? (a_days+4) % 7 : (a_days+5) % 7 + 6;
    }

    /// Returns day of week in civil calendar for y-m-d date. [0, 6] -> [Sun, Sat].
    constexpr int weekday(int y, int m, int d) {
		constexpr int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
		y -= m < 3;
		return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
	}

    /// Convert y/m/d into seconds since epoch 1970-1-1
    inline time_t mktime_utc(int y, unsigned m, unsigned d) {
        return to_gregorian_days(y, m, d) * 86400;
    }

    /// Convert date into seconds since epoch 1970-1-1
    inline time_t mktime_utc(int      year, unsigned month, unsigned day,
                             unsigned hour, unsigned min,   unsigned sec) {
        time_t res = to_gregorian_days(year, month, day) * 86400;
        res += 3600*hour + 60*min + sec;
        return res;
    }

    /// Convert tm structure into time since epoch 1970-1-1
    inline time_t mktime_utc(struct tm *tm) {
        return mktime_utc(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
                          tm->tm_hour, tm->tm_min, tm->tm_sec);
    }

#if __cplusplus >= 201103L

    // Example maketm_utc(std::chrono::system_clock::now())
    template <class Duration>
    std::tm
    to_tm_utc(std::chrono::time_point<std::chrono::system_clock, Duration> tp)
    {
        using period = std::ratio_multiply<
                        std::chrono::hours::period,
                        std::ratio<24>>;
        using days   = std::chrono::duration<int, period>;
        // t is time duration since 1970-01-01
        Duration t = tp.time_since_epoch();
        // d is days since 1970-01-01
        days d = round_down<days>(t);
        // t is now time duration since midnight of day d
        t -= d;
        // break d down into year/month/day
        int year, month, day;
        std::tie(year, month, day) = from_gregorian_days(d.count());

        int h  = std::chrono::duration_cast<std::chrono::hours>(t).count();
            t -= std::chrono::hours(tp);
        int m  = std::chrono::duration_cast<std::chrono::minutes>(t).count();
            t -= std::chrono::minutes(tp);
        int s  = std::chrono::duration_cast<std::chrono::seconds>(t).count();

        std::tm tm = {
            s, m, h, day, month-1, year-1900,
            weekday_from_days(d.count()), d.count() - to_gregorian_days(year,1,1),
            0, 0, 0
        };

        return tm;
    }

#endif

    //----------------------------------------------------------------------------
    /// Parse time in format "HH:MM[:SS][am|pm]" to seconds since midnight
    //----------------------------------------------------------------------------
    long parse_time_to_seconds(const char* a_tm, int a_sz = -1);

    //----------------------------------------------------------------------------
    /// Parse day of week "Sun" to "Sat" (case insensitive).
    /// Also accept "tod" and "today" for today's day.
    /// @param a_str       input string
    /// @param a_today_dow DOW of today, if known
    /// @param a_utc       use UTC timezone (only used when a_str is "tod[ay]" and
    ///                    \a a_today_dow is -1)
    /// @return 0-6 for Sun-Sat, or -1 for bad input. a_str is advanced to the end
    ///         of parsed input.
    //----------------------------------------------------------------------------
    int parse_dow_ref(const char*& a_str, int a_today_dow=-1, bool a_utc=false);

    inline int parse_dow(const char* a_str, int a_tod_dow=-1, bool a_utc=false) {
        return parse_dow_ref(a_str, a_tod_dow, a_utc);
    }

#ifdef _WIN32
    /// Simulated support of strptime(3) on Windows
    /// \see strptime(3)
    inline char* strptime(const char* str, const char* fmt, struct tm*  tm) {
        std::istringstream input(str);
        input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
        input >> std::get_time(tm, fmt);
        return input.fail() ? nullptr : (char*)(str + input.tellg());
    }
#endif

} // namespace utxx
<|endoftext|>


<commit_before>#include "Zenderer/Graphics/Effect.hpp"

using namespace zen;

using util::CLog;
using util::LogMode;

using gfx::CEffect;
using gfx::EffectType;

CEffect::CEffect(const EffectType Type, asset::CAssetManager& Assets) :
    CGLSubsystem("ShaderSet"),
    m_Log(CLog::GetEngineLog()),
    m_Shader(Assets), m_type(Type)
{
}

CEffect::~CEffect()
{
    this->Destroy();
}

bool CEffect::Init()
{
    if(m_init) return true;

    // m_type is guaranteed to be valid, except for counter.
    if(m_type == EffectType::ZEN_EFFECT_COUNT)
    {
        m_Log << m_Log.SetMode(LogMode::ZEN_ERROR) << m_Log.SetSystem("Effect")
              << "ZEN_EFFECT_COUNT is not a valid effect." << CLog::endl;
        return (m_init = false);
    }

#ifdef ZEN_DEBUG_BUILD
    // All effects currently use the default vertex shader.
    m_Shader.LoadVertexShaderFromFile(ZENDERER_SHADER_PATH"Default.vs");

    if(m_type == EffectType::NO_EFFECT)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"Default.fs");

    else if(m_type == EffectType::GAUSSIAN_BLUR_H)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"GaussianBlurH.fs");

    else if(m_type == EffectType::GAUSSIAN_BLUR_V)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"GaussianBlurV.fs");

    else if(m_type == EffectType::GRAYSCALE)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"Grayscale.fs");

    else if(m_type == EffectType::SPRITESHEET)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"SpriteSheet.fs");

    else if(m_type == EffectType::RIPPLE)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"Ripple.fs");
#else
    // All effects currently use the default vertex shader.
    m_Shader.LoadVertexShaderFromStr(gfxcore::DEFAULT_VS);

    if(m_type == EffectType::NO_EFFECT)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::DEFAULT_FS);

    else if(m_type == EffectType::GAUSSIAN_BLUR_H)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::GAUSSIANBLURH_FS);

    else if(m_type == EffectType::GAUSSIAN_BLUR_V)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::GAUSSIANBLURV_FS);

    else if(m_type == EffectType::GRAYSCALE)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::GRAYSCALE_FS);

    else if(m_type == EffectType::SPRITESHEET)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::SPRITESHEET_FS);

    else if(m_type == EffectType::RIPPLE)
        m_init = m_Shader.LoadFragmentShaderFromFile(gfxcore::RIPPLE_FS);

#endif // ZEN_DEBUG_BUILD

    else if(m_type == EffectType::CUSTOM_EFFECT)
    {
        // Custom effects are only loaded from files via `CMaterial` class.
        m_Log   << m_Log.SetMode(LogMode::ZEN_FATAL) << m_Log.SetSystem("Effect")
                << "Custom effects can only be loaded from .zfx files via the "
                <<  "zen::gfx::CMaterial object." << CLog::endl;

        return(m_init = false);
    }

    else
    {
        // Fatal error because this shouldn't be possible.
        m_Log   << m_Log.SetMode(LogMode::ZEN_FATAL) << m_Log.SetSystem("Effect")
                << "Invalid effect type: " << static_cast<int16_t>(m_type)
                << "." << CLog::endl;

        return (m_init = false);
    }

    return (m_init = m_Shader.CreateShaderObject());
}

bool CEffect::Destroy()
{
    // We keep the type to Init() again.
    m_Shader.Destroy();
    return !(m_init = m_Shader.GetShaderObject() != 0);
}

bool CEffect::SetParameter(const string_t& name,
                           const real_t* pValues,
                           const size_t count)
{
    ZEN_ASSERT(!name.empty());
    ZEN_ASSERT(pValues != nullptr);
    ZEN_ASSERT(count > 0);

    if(!this->Init()) return false;

    GLint loc = m_Shader.GetUniformLocation(name);
    if(loc == -1) return false;

    if(count == 1)      { GL(glUniform1f(loc, pValues[0]));  }
    else if(count == 2) { GL(glUniform2fv(loc, 1, pValues)); }
    else if(count == 3) { GL(glUniform3fv(loc, 1, pValues)); }
    else if(count == 4) { GL(glUniform4fv(loc, 1, pValues)); }
    else
    {
        m_Log   << m_Log.SetMode(LogMode::ZEN_ERROR)
                << m_Log.SetSystem("Effect")
                << "No appropriate parameter switch found for " << count
                << " real values." << CLog::endl;
        return false;
    }

    return true;
}

bool CEffect::SetParameter(const string_t& name,
                           const int* pValues,
                           const size_t count)
{
    ZEN_ASSERT(!name.empty());
    ZEN_ASSERT(pValues != nullptr);
    ZEN_ASSERT(count > 0);

    if(!this->Init()) return false;

    GLint loc = m_Shader.GetUniformLocation(name);
    if(loc == -1) return false;

    if(count == 1)      { GL(glUniform1i(loc, pValues[0]));  }
    else if(count == 2) { GL(glUniform2iv(loc, 1, pValues)); }
    else if(count == 3) { GL(glUniform3iv(loc, 1, pValues)); }
    else if(count == 4) { GL(glUniform4iv(loc, 1, pValues)); }
    else
    {
        m_Log   << m_Log.SetMode(LogMode::ZEN_ERROR)
                << m_Log.SetSystem("Effect")
                << "No appropriate parameter switch found for " << count
                << " integer values." << CLog::endl;
        return false;
    }

    return true;
}

bool CEffect::SetParameter(const string_t& name,
                           const math::matrix4x4_t& Matrix)
{
    ZEN_ASSERT(!name.empty());

    if(!this->Init()) return false;

    GLint loc = m_Shader.GetUniformLocation(name);
    GL(glUniformMatrix4fv(loc, 1, GL_TRUE, Matrix.GetPointer()));
    return (loc != -1);
}

bool CEffect::LoadCustomEffect(const string_t& vs, const string_t& fs)
{
    ZEN_ASSERT(m_type == EffectType::CUSTOM_EFFECT);

    if(m_init) this->Destroy();
    m_init = m_Shader.LoadFromFile(vs, fs) && m_Shader.CreateShaderObject();
    return m_init;
}
<commit_msg>Disabled loading raw shader strings; unknown bugs.<commit_after>#include "Zenderer/Graphics/Effect.hpp"

using namespace zen;

using util::CLog;
using util::LogMode;

using gfx::CEffect;
using gfx::EffectType;

CEffect::CEffect(const EffectType Type, asset::CAssetManager& Assets) :
    CGLSubsystem("ShaderSet"),
    m_Log(CLog::GetEngineLog()),
    m_Shader(Assets), m_type(Type)
{
}

CEffect::~CEffect()
{
    this->Destroy();
}

bool CEffect::Init()
{
    if(m_init) return true;

    // m_type is guaranteed to be valid, except for counter.
    if(m_type == EffectType::ZEN_EFFECT_COUNT)
    {
        m_Log << m_Log.SetMode(LogMode::ZEN_ERROR) << m_Log.SetSystem("Effect")
              << "ZEN_EFFECT_COUNT is not a valid effect." << CLog::endl;
        return (m_init = false);
    }

//#ifdef ZEN_DEBUG_BUILD
    // All effects currently use the default vertex shader.
    m_Shader.LoadVertexShaderFromFile(ZENDERER_SHADER_PATH"Default.vs");

    if(m_type == EffectType::NO_EFFECT)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"Default.fs");

    else if(m_type == EffectType::GAUSSIAN_BLUR_H)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"GaussianBlurH.fs");

    else if(m_type == EffectType::GAUSSIAN_BLUR_V)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"GaussianBlurV.fs");

    else if(m_type == EffectType::GRAYSCALE)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"Grayscale.fs");

    else if(m_type == EffectType::SPRITESHEET)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"SpriteSheet.fs");

    else if(m_type == EffectType::RIPPLE)
        m_init = m_Shader.LoadFragmentShaderFromFile(
            ZENDERER_SHADER_PATH"Ripple.fs");
    /*
#else
    // All effects currently use the default vertex shader.
    m_Shader.LoadVertexShaderFromStr(gfxcore::DEFAULT_VS);

    if(m_type == EffectType::NO_EFFECT)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::DEFAULT_FS);

    else if(m_type == EffectType::GAUSSIAN_BLUR_H)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::GAUSSIANBLURH_FS);

    else if(m_type == EffectType::GAUSSIAN_BLUR_V)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::GAUSSIANBLURV_FS);

    else if(m_type == EffectType::GRAYSCALE)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::GRAYSCALE_FS);

    else if(m_type == EffectType::SPRITESHEET)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::SPRITESHEET_FS);

    else if(m_type == EffectType::RIPPLE)
        m_init = m_Shader.LoadFragmentShaderFromStr(gfxcore::RIPPLE_FS);

#endif // ZEN_DEBUG_BUILD
    */

    else if(m_type == EffectType::CUSTOM_EFFECT)
    {
        // Custom effects are only loaded from files via `CMaterial` class.
        m_Log   << m_Log.SetMode(LogMode::ZEN_FATAL) << m_Log.SetSystem("Effect")
                << "Custom effects can only be loaded from .zfx files via the "
                <<  "zen::gfx::CMaterial object." << CLog::endl;

        return(m_init = false);
    }

    else
    {
        // Fatal error because this shouldn't be possible.
        m_Log   << m_Log.SetMode(LogMode::ZEN_FATAL) << m_Log.SetSystem("Effect")
                << "Invalid effect type: " << static_cast<int16_t>(m_type)
                << "." << CLog::endl;

        return (m_init = false);
    }

    return (m_init = m_Shader.CreateShaderObject());
}

bool CEffect::Destroy()
{
    // We keep the type to Init() again.
    m_Shader.Destroy();
    return !(m_init = m_Shader.GetShaderObject() != 0);
}

bool CEffect::SetParameter(const string_t& name,
                           const real_t* pValues,
                           const size_t count)
{
    ZEN_ASSERT(!name.empty());
    ZEN_ASSERT(pValues != nullptr);
    ZEN_ASSERT(count > 0);

    if(!this->Init()) return false;

    GLint loc = m_Shader.GetUniformLocation(name);
    if(loc == -1) return false;

    if(count == 1)      { GL(glUniform1f(loc, pValues[0]));  }
    else if(count == 2) { GL(glUniform2fv(loc, 1, pValues)); }
    else if(count == 3) { GL(glUniform3fv(loc, 1, pValues)); }
    else if(count == 4) { GL(glUniform4fv(loc, 1, pValues)); }
    else
    {
        m_Log   << m_Log.SetMode(LogMode::ZEN_ERROR)
                << m_Log.SetSystem("Effect")
                << "No appropriate parameter switch found for " << count
                << " real values." << CLog::endl;
        return false;
    }

    return true;
}

bool CEffect::SetParameter(const string_t& name,
                           const int* pValues,
                           const size_t count)
{
    ZEN_ASSERT(!name.empty());
    ZEN_ASSERT(pValues != nullptr);
    ZEN_ASSERT(count > 0);

    if(!this->Init()) return false;

    GLint loc = m_Shader.GetUniformLocation(name);
    if(loc == -1) return false;

    if(count == 1)      { GL(glUniform1i(loc, pValues[0]));  }
    else if(count == 2) { GL(glUniform2iv(loc, 1, pValues)); }
    else if(count == 3) { GL(glUniform3iv(loc, 1, pValues)); }
    else if(count == 4) { GL(glUniform4iv(loc, 1, pValues)); }
    else
    {
        m_Log   << m_Log.SetMode(LogMode::ZEN_ERROR)
                << m_Log.SetSystem("Effect")
                << "No appropriate parameter switch found for " << count
                << " integer values." << CLog::endl;
        return false;
    }

    return true;
}

bool CEffect::SetParameter(const string_t& name,
                           const math::matrix4x4_t& Matrix)
{
    ZEN_ASSERT(!name.empty());

    if(!this->Init()) return false;

    GLint loc = m_Shader.GetUniformLocation(name);
    GL(glUniformMatrix4fv(loc, 1, GL_TRUE, Matrix.GetPointer()));
    return (loc != -1);
}

bool CEffect::LoadCustomEffect(const string_t& vs, const string_t& fs)
{
    ZEN_ASSERT(m_type == EffectType::CUSTOM_EFFECT);

    if(m_init) this->Destroy();
    m_init = m_Shader.LoadFromFile(vs, fs) && m_Shader.CreateShaderObject();
    return m_init;
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2016 Liav Turkia

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.
*/
#include <MACE/Core/Constants.h>

#include <MACE/Graphics/Window.h>
#include <MACE/Graphics/Renderer.h>

#include <MACE/Utility/BitField.h>

#include <mutex>
#include <ctime>
#include <chrono>
#include <iostream>
#include <unordered_map>
#include <sstream>

#include <GLFW/glfw3.h>

#include <GL/glew.h>

namespace mc {
	namespace os {
		namespace {
			std::unordered_map< short int, BitField > keys = std::unordered_map< short int, BitField >();

			int mouseX = -1;
			int mouseY = -1;

			double scrollX = 0;
			double scrollY = 0;

			void pushKeyEvent(const short int& key, const BitField action) {
				keys[key] = action;
			}
		}//anon namespace

		WindowModule::WindowModule(const int width, const int height, const char* windowTitle) : title(windowTitle), originalWidth(width), originalHeight(height) {}

		void WindowModule::create() {
			window = glfwCreateWindow(originalWidth, originalHeight, title.c_str(), NULL, NULL);

			//first we set up glew and opengl
			glfwMakeContextCurrent(window);

			gfx::ogl::checkGLError(__LINE__, __FILE__);

			glewExperimental = true;
			GLenum result = glewInit();
			if( result != GLEW_OK ) {
				std::ostringstream errorMessage;
				errorMessage << "GLEW failed to initialize: ";
				//to convert from GLubyte* to string, we can use the << in ostream. For some reason the
				//+ operater in std::string can not handle this conversion.
				errorMessage << glewGetErrorString(result);
				throw mc::InitializationError(errorMessage.str());
			}

			try {
				gfx::ogl::checkGLError(__LINE__, __FILE__);
			} catch( ... ) {
				//glew sometimes throws errors that can be ignored (GL_INVALID_ENUM)
			}

			if( !GLEW_VERSION_3_0 ) {
				throw mc::InitializationError("OpenGL 3.0+ not found");
			} else if( !GLEW_VERSION_3_3 ) {
				std::cerr << "OpenGL 3.3 not found, falling back to OpenGL 3.0, which may cause undefined results. Try updating your graphics driver to fix this.";
			} else {
				std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
				std::cout << "OpenGL has been created succesfully!" << std::endl;
				std::cout << "Version: " << std::endl << "	" << glGetString(GL_VERSION) << std::endl;
				std::cout << "Vendor: " << std::endl << "	" << glGetString(GL_VENDOR) << std::endl;
				std::cout << "Renderer: " << std::endl << "	" << glGetString(GL_RENDERER) << std::endl;
				std::cout << "Shader version: " << std::endl << "	" << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
				std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
			}

			gfx::ogl::checkGLError(__LINE__, __FILE__);

			if( vsync )glfwSwapInterval(1);
			else glfwSwapInterval(0);

			glfwSetWindowUserPointer(window, this);

			auto closeCallback = [] (GLFWwindow* window) {
				static_cast<WindowModule*>(glfwGetWindowUserPointer(window))->makeDirty();

				mc::MACE::requestStop();
			};
			glfwSetWindowCloseCallback(window, closeCallback);

			auto keyDown = [] (GLFWwindow*, int key, int, int action, int mods) {
				BitField actions = BitField(0);
				actions.setBit(Input::PRESSED, action == GLFW_PRESS);
				actions.setBit(Input::REPEATED, action == GLFW_REPEAT);
				actions.setBit(Input::RELEASED, action == GLFW_RELEASE);
				actions.setBit(Input::MOD_SHIFT, (mods & GLFW_MOD_SHIFT) != 0);
				actions.setBit(Input::MOD_CONTROL, (mods & GLFW_MOD_CONTROL) != 0);
				actions.setBit(Input::MOD_ALT, (mods & GLFW_MOD_ALT) != 0);
				actions.setBit(Input::MOD_SUPER, (mods & GLFW_MOD_SUPER) != 0);

				pushKeyEvent(static_cast<short int>(key), actions);
			};
			glfwSetKeyCallback(window, keyDown);

			auto mouseDown = [] (GLFWwindow*, int button, int action, int mods) {
				BitField actions = BitField(0);
				actions.setBit(Input::PRESSED, action == GLFW_PRESS);
				actions.setBit(Input::REPEATED, action == GLFW_REPEAT);
				actions.setBit(Input::RELEASED, action == GLFW_RELEASE);
				actions.setBit(Input::MOD_SHIFT, (mods & GLFW_MOD_SHIFT) != 0);
				actions.setBit(Input::MOD_CONTROL, (mods & GLFW_MOD_CONTROL) != 0);
				actions.setBit(Input::MOD_ALT, (mods & GLFW_MOD_ALT) != 0);
				actions.setBit(Input::MOD_SUPER, (mods & GLFW_MOD_SUPER) != 0);

				//in case that we dont have it mapped the same way that GLFW does, we add MOUSE_FIRST which is the offset to the mouse bindings.
				pushKeyEvent(static_cast<short int>(button) + Input::MOUSE_FIRST, actions);
			};
			glfwSetMouseButtonCallback(window, mouseDown);

			auto cursorPosition = [] (GLFWwindow*, double xpos, double ypos) {
				mouseX = static_cast<int>(mc::math::floor(xpos));
				mouseY = static_cast<int>(mc::math::floor(ypos));
			};
			glfwSetCursorPosCallback(window, cursorPosition);

			auto scrollWheel = [] (GLFWwindow*, double xoffset, double yoffset) {
				scrollY = yoffset;
				scrollX = xoffset;
			};
			glfwSetScrollCallback(window, scrollWheel);

			auto framebufferResize = [] (GLFWwindow* window, int width, int height) {
				gfx::Renderer::resize(width, height);
				static_cast<WindowModule*>(glfwGetWindowUserPointer(window))->makeDirty();
			};
			glfwSetFramebufferSizeCallback(window, framebufferResize);

			auto windowDamaged = [] (GLFWwindow* window) {
				static_cast<WindowModule*>(glfwGetWindowUserPointer(window))->makeDirty();
			};
			glfwSetWindowRefreshCallback(window, windowDamaged);

			int width = 0, height = 0;

			glfwGetFramebufferSize(window, &width, &height);

			gfx::Renderer::init(width, height);

			creationCallback();
		}//create

		GLFWwindow* WindowModule::getGLFWWindow() {
			return window;
		}

		const unsigned int & WindowModule::getFPS() const {
			return fps;
		}

		void WindowModule::setFPS(const unsigned int & FPS) {
			fps = FPS;
		}

		const int WindowModule::getOriginalWidth() const {
			return originalWidth;
		}
		const int WindowModule::getOriginalHeight() const {
			return originalHeight;
		}
		std::string WindowModule::getTitle() {
			return title;
		}
		const std::string WindowModule::getTitle() const {
			return title;
		}
		void WindowModule::setTitle(const std::string & newTitle) {
			glfwSetWindowTitle(window, newTitle.c_str());
		}

		void WindowModule::threadCallback() {
			//mutex for this function.
			std::mutex mutex;

			//now is set to be time(0) every loop, and the delta is calculated from now nad last frame.
			time_t now = time(0);
			//each time the frame is swapped, lastFrame is updated with the new time
			time_t lastFrame = time(0);

			//this stores how many milliseconds it takes for the frame to swap. it is 1 by default so it doesnt create an infinite loop
			float windowDelay = 0;

			try {
				std::unique_lock<std::mutex> guard(mutex);//in case there is an exception, the unique lock will unlock the mutex

				create();

				Entity::init();

				if( fps != 0.0f ) {
					windowDelay = 1000.0f / static_cast<float>(fps);
				}
			} catch( const std::exception& e ) {
				Exception::handleException(e);
			} catch( ... ) {
				std::cerr << "An error has occured";
				MACE::requestStop();
			}

			//this is the main rendering loop.
			//we loop infinitely until break is called. break is called when an exception is thrown or MACE::isRunning is false
			for( ;;) {//( ;_;)
				try {

					{
						//thread doesn't own window, so we have to lock the mutex
						std::unique_lock<std::mutex> guard(mutex);//in case there is an exception, the unique lock will unlock the mutex

						glfwPollEvents();

						if( getProperty(Entity::DIRTY) ) {
							gfx::Renderer::clearBuffers();

							Entity::render();

							gfx::Renderer::renderFrame(this);
						}

						gfx::Renderer::checkInput();

						if( !MACE::isRunning() ) {
							break; // while (!MACE::isRunning) would require a lock on destroyed or have it be an atomic varible, both of which are undesirable. while we already have a lock, set a stack variable to false.that way, we only read it, and we dont need to always lock it
						}

					}
					now = time(0);

					const time_t delta = now - lastFrame;

					if( delta < windowDelay ) {
						lastFrame = now;

						std::this_thread::sleep_for(std::chrono::milliseconds((unsigned int) windowDelay));
					}
				} catch( const std::exception& e ) {
					Exception::handleException(e);
					break;
				} catch( ... ) {
					std::cerr << "An error has occured";
					MACE::requestStop();
					break;
				}
			}

			{
				std::unique_lock<std::mutex> guard(mutex);//in case there is an exception, the unique lock will unlock the mutex
				try {
					Entity::destroy();

					gfx::Renderer::destroy();

					glfwDestroyWindow(window);
				} catch( const std::exception& e ) {
					Exception::handleException(e);
				} catch( ... ) {
					std::cerr << "An error has occured";
					MACE::requestStop();
				}
			}

		}//threadCallback

		void WindowModule::init() {
			if( !glfwInit() ) {
				throw InitializationError("GLFW failed to initialize!");
			}

			windowThread = std::thread(&WindowModule::threadCallback, this);
		}

		void WindowModule::update() {
			std::mutex mutex;
			std::unique_lock<std::mutex> guard(mutex);

			Entity::update();
		}//update

		void WindowModule::destroy() {
			destroyed = true;
			windowThread.join();

			glfwTerminate();
		}//destroy

		std::string WindowModule::getName() const {
			return "MACE/Window";
		}//getName()

		void WindowModule::setVSync(const bool & sync) {
			vsync = sync;
		}//setVSync

		bool WindowModule::isVSync() const {
			return vsync;
		}//isVSync

		void WindowModule::setCreationCallback(const VoidFunctionPtr callback) {
			creationCallback = callback;
		}//setCreationCallback

		const VoidFunctionPtr WindowModule::getCreationCallback() const {
			return creationCallback;
		}//getCreationCallback

		VoidFunctionPtr WindowModule::getCreationCallback() {
			return creationCallback;
		}//getCreationCallback

		void WindowModule::onInit() {}

		void WindowModule::onUpdate() {}

		void WindowModule::onRender() {}

		void WindowModule::onDestroy() {}

		void WindowModule::clean() {
			setProperty(Entity::DIRTY, false);
		}//clean()

		namespace Input {
			const BitField & getKey(const short int key) {
				return keys[key];
			}

			bool isKeyDown(const short int key) {
				return keys[key].getBit(Input::PRESSED) || keys[key].getBit(Input::REPEATED);
			}

			bool isKeyRepeated(const short int key) {
				return keys[key].getBit(Input::REPEATED);
			}

			bool isKeyReleased(const short int key) {
				return keys[key].getBit(Input::RELEASED);
			}
			int getMouseX() noexcept {
				return mouseX;
			}
			int getMouseY() noexcept {
				return mouseY;
			}
			double getScrollVertical() noexcept {
				return scrollY;
			}
			double getScrollHorizontal() noexcept {
				return scrollX;
			}
		}//Input
	}//os
}//mc
<commit_msg>Improved failed opengl context error message<commit_after>/*
The MIT License (MIT)

Copyright (c) 2016 Liav Turkia

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.
*/
#include <MACE/Core/Constants.h>

#include <MACE/Graphics/Window.h>
#include <MACE/Graphics/Renderer.h>

#include <MACE/Utility/BitField.h>

#include <mutex>
#include <ctime>
#include <chrono>
#include <iostream>
#include <unordered_map>
#include <sstream>

#include <GLFW/glfw3.h>

#include <GL/glew.h>

namespace mc {
	namespace os {
		namespace {
			std::unordered_map< short int, BitField > keys = std::unordered_map< short int, BitField >();

			int mouseX = -1;
			int mouseY = -1;

			double scrollX = 0;
			double scrollY = 0;

			void pushKeyEvent(const short int& key, const BitField action) {
				keys[key] = action;
			}
		}//anon namespace

		WindowModule::WindowModule(const int width, const int height, const char* windowTitle) : title(windowTitle), originalWidth(width), originalHeight(height) {}

		void WindowModule::create() {
			window = glfwCreateWindow(originalWidth, originalHeight, title.c_str(), NULL, NULL);

			//first we set up glew and opengl
			glfwMakeContextCurrent(window);

			gfx::ogl::checkGLError(__LINE__, __FILE__);

			glewExperimental = true;
			GLenum result = glewInit();
			if( result != GLEW_OK ) {
				std::ostringstream errorMessage;
				errorMessage << "GLEW failed to initialize: ";
				//to convert from GLubyte* to string, we can use the << in ostream. For some reason the
				//+ operater in std::string can not handle this conversion.
				errorMessage << glewGetErrorString(result);
				throw mc::InitializationError(errorMessage.str());
			}

			try {
				gfx::ogl::checkGLError(__LINE__, __FILE__);
			} catch( ... ) {
				//glew sometimes throws errors that can be ignored (GL_INVALID_ENUM)
			}

			if( !GLEW_VERSION_3_0 ) {
				std::ostringstream errorMessage;
				errorMessage << "OpenGL 3.0+ not found. " << std::endl;
				errorMessage << glGetString(GL_VERSION) << " was found instead." << std::endl;
				errorMessage << "This graphics card is not supported." << std::endl;
				//to convert from GLubyte* to string, we can use the << in ostream. For some reason the
				//+ operater in std::string can not handle this conversion.
				throw mc::InitializationError(errorMessage.str());
			} else if( !GLEW_VERSION_3_3 ) {
				std::cerr << "OpenGL 3.3 not found, falling back to OpenGL 3.0, which may cause undefined results. Try updating your graphics driver to fix this.";
			} else {
				std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
				std::cout << "OpenGL has been created succesfully!" << std::endl;
				std::cout << "Version: " << std::endl << "	" << glGetString(GL_VERSION) << std::endl;
				std::cout << "Vendor: " << std::endl << "	" << glGetString(GL_VENDOR) << std::endl;
				std::cout << "Renderer: " << std::endl << "	" << glGetString(GL_RENDERER) << std::endl;
				std::cout << "Shader version: " << std::endl << "	" << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
				std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
			}

			gfx::ogl::checkGLError(__LINE__, __FILE__);

			if( vsync )glfwSwapInterval(1);
			else glfwSwapInterval(0);

			glfwSetWindowUserPointer(window, this);

			auto closeCallback = [] (GLFWwindow* window) {
				static_cast<WindowModule*>(glfwGetWindowUserPointer(window))->makeDirty();

				mc::MACE::requestStop();
			};
			glfwSetWindowCloseCallback(window, closeCallback);

			auto keyDown = [] (GLFWwindow*, int key, int, int action, int mods) {
				BitField actions = BitField(0);
				actions.setBit(Input::PRESSED, action == GLFW_PRESS);
				actions.setBit(Input::REPEATED, action == GLFW_REPEAT);
				actions.setBit(Input::RELEASED, action == GLFW_RELEASE);
				actions.setBit(Input::MOD_SHIFT, (mods & GLFW_MOD_SHIFT) != 0);
				actions.setBit(Input::MOD_CONTROL, (mods & GLFW_MOD_CONTROL) != 0);
				actions.setBit(Input::MOD_ALT, (mods & GLFW_MOD_ALT) != 0);
				actions.setBit(Input::MOD_SUPER, (mods & GLFW_MOD_SUPER) != 0);

				pushKeyEvent(static_cast<short int>(key), actions);
			};
			glfwSetKeyCallback(window, keyDown);

			auto mouseDown = [] (GLFWwindow*, int button, int action, int mods) {
				BitField actions = BitField(0);
				actions.setBit(Input::PRESSED, action == GLFW_PRESS);
				actions.setBit(Input::REPEATED, action == GLFW_REPEAT);
				actions.setBit(Input::RELEASED, action == GLFW_RELEASE);
				actions.setBit(Input::MOD_SHIFT, (mods & GLFW_MOD_SHIFT) != 0);
				actions.setBit(Input::MOD_CONTROL, (mods & GLFW_MOD_CONTROL) != 0);
				actions.setBit(Input::MOD_ALT, (mods & GLFW_MOD_ALT) != 0);
				actions.setBit(Input::MOD_SUPER, (mods & GLFW_MOD_SUPER) != 0);

				//in case that we dont have it mapped the same way that GLFW does, we add MOUSE_FIRST which is the offset to the mouse bindings.
				pushKeyEvent(static_cast<short int>(button) + Input::MOUSE_FIRST, actions);
			};
			glfwSetMouseButtonCallback(window, mouseDown);

			auto cursorPosition = [] (GLFWwindow*, double xpos, double ypos) {
				mouseX = static_cast<int>(mc::math::floor(xpos));
				mouseY = static_cast<int>(mc::math::floor(ypos));
			};
			glfwSetCursorPosCallback(window, cursorPosition);

			auto scrollWheel = [] (GLFWwindow*, double xoffset, double yoffset) {
				scrollY = yoffset;
				scrollX = xoffset;
			};
			glfwSetScrollCallback(window, scrollWheel);

			auto framebufferResize = [] (GLFWwindow* window, int width, int height) {
				gfx::Renderer::resize(width, height);
				static_cast<WindowModule*>(glfwGetWindowUserPointer(window))->makeDirty();
			};
			glfwSetFramebufferSizeCallback(window, framebufferResize);

			auto windowDamaged = [] (GLFWwindow* window) {
				static_cast<WindowModule*>(glfwGetWindowUserPointer(window))->makeDirty();
			};
			glfwSetWindowRefreshCallback(window, windowDamaged);

			int width = 0, height = 0;

			glfwGetFramebufferSize(window, &width, &height);

			gfx::Renderer::init(width, height);

			creationCallback();
		}//create

		GLFWwindow* WindowModule::getGLFWWindow() {
			return window;
		}

		const unsigned int & WindowModule::getFPS() const {
			return fps;
		}

		void WindowModule::setFPS(const unsigned int & FPS) {
			fps = FPS;
		}

		const int WindowModule::getOriginalWidth() const {
			return originalWidth;
		}
		const int WindowModule::getOriginalHeight() const {
			return originalHeight;
		}
		std::string WindowModule::getTitle() {
			return title;
		}
		const std::string WindowModule::getTitle() const {
			return title;
		}
		void WindowModule::setTitle(const std::string & newTitle) {
			glfwSetWindowTitle(window, newTitle.c_str());
		}

		void WindowModule::threadCallback() {
			//mutex for this function.
			std::mutex mutex;

			//now is set to be time(0) every loop, and the delta is calculated from now nad last frame.
			time_t now = time(0);
			//each time the frame is swapped, lastFrame is updated with the new time
			time_t lastFrame = time(0);

			//this stores how many milliseconds it takes for the frame to swap. it is 1 by default so it doesnt create an infinite loop
			float windowDelay = 0;

			try {
				std::unique_lock<std::mutex> guard(mutex);//in case there is an exception, the unique lock will unlock the mutex

				create();

				Entity::init();

				if( fps != 0.0f ) {
					windowDelay = 1000.0f / static_cast<float>(fps);
				}
			} catch( const std::exception& e ) {
				Exception::handleException(e);
			} catch( ... ) {
				std::cerr << "An error has occured";
				MACE::requestStop();
			}

			//this is the main rendering loop.
			//we loop infinitely until break is called. break is called when an exception is thrown or MACE::isRunning is false
			for( ;;) {//( ;_;)
				try {

					{
						//thread doesn't own window, so we have to lock the mutex
						std::unique_lock<std::mutex> guard(mutex);//in case there is an exception, the unique lock will unlock the mutex

						glfwPollEvents();

						if( getProperty(Entity::DIRTY) ) {
							gfx::Renderer::clearBuffers();

							Entity::render();

							gfx::Renderer::renderFrame(this);
						}

						gfx::Renderer::checkInput();

						if( !MACE::isRunning() ) {
							break; // while (!MACE::isRunning) would require a lock on destroyed or have it be an atomic varible, both of which are undesirable. while we already have a lock, set a stack variable to false.that way, we only read it, and we dont need to always lock it
						}

					}
					now = time(0);

					const time_t delta = now - lastFrame;

					if( delta < windowDelay ) {
						lastFrame = now;

						std::this_thread::sleep_for(std::chrono::milliseconds((unsigned int) windowDelay));
					}
				} catch( const std::exception& e ) {
					Exception::handleException(e);
					break;
				} catch( ... ) {
					std::cerr << "An error has occured";
					MACE::requestStop();
					break;
				}
			}

			{
				std::unique_lock<std::mutex> guard(mutex);//in case there is an exception, the unique lock will unlock the mutex
				try {
					Entity::destroy();

					gfx::Renderer::destroy();

					glfwDestroyWindow(window);
				} catch( const std::exception& e ) {
					Exception::handleException(e);
				} catch( ... ) {
					std::cerr << "An error has occured";
					MACE::requestStop();
				}
			}

		}//threadCallback

		void WindowModule::init() {
			if( !glfwInit() ) {
				throw InitializationError("GLFW failed to initialize!");
			}

			windowThread = std::thread(&WindowModule::threadCallback, this);
		}

		void WindowModule::update() {
			std::mutex mutex;
			std::unique_lock<std::mutex> guard(mutex);

			Entity::update();
		}//update

		void WindowModule::destroy() {
			destroyed = true;
			windowThread.join();

			glfwTerminate();
		}//destroy

		std::string WindowModule::getName() const {
			return "MACE/Window";
		}//getName()

		void WindowModule::setVSync(const bool & sync) {
			vsync = sync;
		}//setVSync

		bool WindowModule::isVSync() const {
			return vsync;
		}//isVSync

		void WindowModule::setCreationCallback(const VoidFunctionPtr callback) {
			creationCallback = callback;
		}//setCreationCallback

		const VoidFunctionPtr WindowModule::getCreationCallback() const {
			return creationCallback;
		}//getCreationCallback

		VoidFunctionPtr WindowModule::getCreationCallback() {
			return creationCallback;
		}//getCreationCallback

		void WindowModule::onInit() {}

		void WindowModule::onUpdate() {}

		void WindowModule::onRender() {}

		void WindowModule::onDestroy() {}

		void WindowModule::clean() {
			setProperty(Entity::DIRTY, false);
		}//clean()

		namespace Input {
			const BitField & getKey(const short int key) {
				return keys[key];
			}

			bool isKeyDown(const short int key) {
				return keys[key].getBit(Input::PRESSED) || keys[key].getBit(Input::REPEATED);
			}

			bool isKeyRepeated(const short int key) {
				return keys[key].getBit(Input::REPEATED);
			}

			bool isKeyReleased(const short int key) {
				return keys[key].getBit(Input::RELEASED);
			}
			int getMouseX() noexcept {
				return mouseX;
			}
			int getMouseY() noexcept {
				return mouseY;
			}
			double getScrollVertical() noexcept {
				return scrollY;
			}
			double getScrollHorizontal() noexcept {
				return scrollX;
			}
		}//Input
	}//os
}//mc
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2012 Sergey Lisitsyn
 * Copyright (C) 2010-2012 Jun Liu, Jieping Ye
 */

#include <shogun/lib/slep/slep_tree_mt_lsr.h>
#include <shogun/mathematics/Math.h>
#include <shogun/lib/slep/tree/altra.h>
#include <shogun/lib/slep/tree/general_altra.h>
#include <shogun/mathematics/lapack.h>

namespace shogun
{

SGMatrix<double> slep_tree_mt_lsr(
		CDotFeatures* features,
		double* y,
		double z,
		const slep_options& options)
{
	int i,j,t;
	int n_feats = features->get_dim_feature_space();
	int n_vecs = features->get_num_vectors();
	double lambda, lambda_max, beta;
	double funcp = 0.0, func = 0.0;

	int n_tasks = options.n_tasks;

	int iter = 1;
	bool done = false;
	bool gradient_break = false;

	double* ATy = SG_CALLOC(double, n_feats*n_tasks);
	for (t=0; t<n_tasks; t++)
	{
		int task_ind_start = options.ind[t]+1;
		int task_ind_end = options.ind[t+1];
		for (i=task_ind_start; i<task_ind_end; i++)
			features->add_to_dense_vec(y[i],i,ATy+t*n_feats,n_feats);
	}

	if (options.regularization!=0)
	{
		if (options.general)
			lambda_max = general_findLambdaMax_mt(ATy, n_feats, n_tasks, options.G, options.ind_t, options.n_nodes);
		else
			lambda_max = findLambdaMax_mt(ATy, n_feats, n_tasks, options.ind_t, options.n_nodes);
		lambda = z*lambda_max;
	}
	else
		lambda = z;

	SGMatrix<double> w(n_feats,n_tasks);
	if (options.initial_w)
	{
		for (j=0; j<n_tasks; j++)
			for (i=0; i<n_feats; i++)
				w(i,j) = options.initial_w[j*n_feats+i];
	}
	else
	{
		for (j=0; j<n_tasks*n_feats; j++)
				w[j] = 0.0;
	}

	double* s = SG_CALLOC(double, n_feats*n_tasks);
	double* g = SG_CALLOC(double, n_feats*n_tasks);
	double* v = SG_CALLOC(double, n_feats*n_tasks);

	double* Aw = SG_CALLOC(double, n_vecs);
	for (t=0; t<n_tasks; t++)
	{
		int task_ind_start = options.ind[t]+1;
		int task_ind_end = options.ind[t+1];
		for (i=task_ind_start; i<task_ind_end; i++)
			Aw[i] = features->dense_dot(i,w.matrix+t*n_feats,n_feats);
	}
	double* Av = SG_MALLOC(double, n_vecs);
	double* As = SG_MALLOC(double, n_vecs);
	double* ATAs = SG_MALLOC(double, n_feats*n_tasks);
	double* resid = SG_MALLOC(double, n_vecs*n_tasks);

	double L = 1.0;

	double* wp = SG_CALLOC(double, n_feats*n_tasks);
	for (i=0; i<n_feats*n_tasks; i++)
		wp[i] = w[i];
	double* Awp = SG_MALLOC(double, n_vecs);
	for (i=0; i<n_vecs; i++)
		Awp[i] = Aw[i];
	double* wwp = SG_CALLOC(double, n_feats*n_tasks);

	double* w_row = SG_MALLOC(double, n_tasks);

	double alphap = 0.0;
	double alpha = 1.0;

	while (!done && iter < options.max_iter)
	{
		beta = (alphap-1.0)/alpha;

		for (i=0; i<n_feats*n_tasks; i++)
			s[i] = w[i] + beta*wwp[i];

		for (i=0; i<n_vecs; i++)
			As[i] = Aw[i] + beta*(Aw[i]-Awp[i]);

		// ATAs = A'*As
		for (i=0; i<n_feats*n_tasks; i++)
			ATAs[i] = 0.0;

		for (t=0; t<n_tasks; t++)
		{
			int task_ind_start = options.ind[t]+1;
			int task_ind_end = options.ind[t+1];
			for (i=task_ind_start; i<task_ind_end; i++)
				features->add_to_dense_vec(As[i],i,ATAs+t*n_feats,n_feats);
		}

		// g = ATAs - ATy
		for (i=0; i<n_feats*n_tasks; i++)
			g[i] = ATAs[i] - ATy[i];

		for (i=0; i<n_feats*n_tasks; i++)
			wp[i] = w[i];

		for (i=0; i<n_vecs; i++)
			Awp[i] = Aw[i];

		while (true)
		{
			// v = s - g / L
			for (i=0; i<n_feats*n_tasks; i++)
				v[i] = s[i] - g[i]*(1.0/L);

			if (options.general)
				general_altra_mt(w.matrix, v, n_feats, n_tasks, options.G, options.ind_t, options.n_nodes, lambda/L);
			else
				altra_mt(w.matrix, v, n_feats, n_tasks, options.ind_t, options.n_nodes, lambda/L);

			// v = x - s
			for (i=0; i<n_feats*n_tasks; i++)
				v[i] = w[i] - s[i];

			for (t=0; t<n_tasks; t++)
			{
				int task_ind_start = options.ind[t]+1;
				int task_ind_end = options.ind[t+1];
				for (i=task_ind_start; i<task_ind_end; i++)
					Aw[i] = features->dense_dot(i,w.matrix+t*n_feats,n_feats);
			}

			for (i=0; i<n_vecs; i++)
				Av[i] = Aw[i] - As[i];

			// squared frobenius norm of r
			double r_sum = SGVector<float64_t>::dot(v,v,n_feats*n_tasks);

			double l_sum = SGVector<float64_t>::dot(Av,Av,n_vecs);

			if (r_sum <= 1e-20)
			{
				gradient_break = true;
				break;
			}

			if (l_sum <= r_sum*L)
				break;
			else
				L = CMath::max(2*L, l_sum/r_sum);
		}

		alphap = alpha;
		alpha = 0.5*(1+CMath::sqrt(4*alpha*alpha+1));

		for (i=0; i<n_feats*n_tasks; i++)
			wwp[i] = w[i] - wp[i];

		// Aw - y
		for (i=0; i<n_vecs; i++)
			resid[i] = Aw[i] - y[i];

		double tree_norm = 0.0;
		for (i=0; i<n_feats; i++)
		{
			for (j=0; j<n_tasks; j++)
				w_row[j] = w(i,j);

			if (options.general)
				tree_norm += general_treeNorm(w_row,n_tasks,options.G,
											 options.ind_t,options.n_nodes);
			else
				tree_norm += treeNorm(w_row,n_tasks,options.ind_t,options.n_nodes);
		}

		funcp = func;
		func = 0.5*SGVector<float64_t>::dot(resid,resid,n_vecs) + lambda*tree_norm;

		if (gradient_break)
			break;

		double norm_wp, norm_wwp;
		double step;
		switch (options.termination)
		{
			case 0:
				if (iter>=2)
				{
					step = CMath::abs(func-funcp);

					if (step <= options.tolerance)
						done = true;
				}
				break;
			case 1:
				if (iter>=2)
				{
					step = CMath::abs(func-funcp);
					if (step <= step*options.tolerance)
						done = true;
				}
				break;
			case 2:
				if (func <= options.tolerance)
					done = true;
				break;
			case 3:
				norm_wwp = CMath::sqrt(SGVector<float64_t>::dot(wwp,wwp,n_feats));
				if (norm_wwp <= options.tolerance)
					done = true;
				break;
			case 4:
				norm_wp = CMath::sqrt(SGVector<float64_t>::dot(wp,wp,n_feats));
				norm_wwp = CMath::sqrt(SGVector<float64_t>::dot(wwp,wwp,n_feats));
				if (norm_wwp <= options.tolerance*CMath::max(norm_wp,1.0))
					done = true;
				break;
			case 5:
				if (iter > options.max_iter)
					done = true;
				break;
			default:
				done = true;
		}

		if (iter%options.restart_num==0)
		{
			alphap = 0.0;
			alpha = 1.0;
			L = 0.5*L;
			for (i=0; i<n_feats; i++)
				wp[i] = w[i];

			for (i=0; i<n_vecs; i++)
				Awp[i] = Aw[i];

			for (i=0; i<n_feats; i++)
				wwp[i] = 0.0;
		}

		iter++;
	}

	SG_FREE(ATy);
	SG_FREE(wp);
	SG_FREE(wwp);
	SG_FREE(s);
	SG_FREE(g);
	SG_FREE(v);
	SG_FREE(Aw);
	SG_FREE(Awp);
	SG_FREE(Av);
	SG_FREE(As);
	SG_FREE(ATAs);
	SG_FREE(resid);
	SG_FREE(w_row);

	return w;
};
};
<commit_msg>Fixes for multitask tree guided least squares<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2012 Sergey Lisitsyn
 * Copyright (C) 2010-2012 Jun Liu, Jieping Ye
 */

#include <shogun/lib/slep/slep_tree_mt_lsr.h>
#include <shogun/mathematics/Math.h>
#include <shogun/lib/slep/tree/altra.h>
#include <shogun/lib/slep/tree/general_altra.h>
#include <shogun/mathematics/lapack.h>

namespace shogun
{

SGMatrix<double> slep_tree_mt_lsr(
		CDotFeatures* features,
		double* y,
		double z,
		const slep_options& options)
{
	int i,j,t;
	int n_feats = features->get_dim_feature_space();
	int n_vecs = features->get_num_vectors();
	double lambda, lambda_max, beta;
	double funcp = 0.0, func = 0.0;

	int n_tasks = options.n_tasks;

	int iter = 1;
	bool done = false;
	bool gradient_break = false;

	double* ATy = SG_CALLOC(double, n_feats*n_tasks);
	for (t=0; t<n_tasks; t++)
	{
		int task_ind_start = options.ind[t];
		int task_ind_end = options.ind[t+1];
		for (i=task_ind_start; i<task_ind_end; i++)
		{
			features->add_to_dense_vec(y[i],i,ATy+t*n_feats,n_feats);
		}
	}

	if (options.regularization!=0)
	{
		if (options.general)
			lambda_max = general_findLambdaMax_mt(ATy, n_feats, n_tasks, options.G, options.ind_t, options.n_nodes);
		else
			lambda_max = findLambdaMax_mt(ATy, n_feats, n_tasks, options.ind_t, options.n_nodes);
		lambda = z*lambda_max;
	}
	else
		lambda = z;

	SGMatrix<double> w(n_feats,n_tasks);
	if (options.initial_w)
	{
		for (j=0; j<n_tasks; j++)
			for (i=0; i<n_feats; i++)
				w(i,j) = options.initial_w[j*n_feats+i];
	}
	else
	{
		for (j=0; j<n_tasks*n_feats; j++)
				w[j] = 0.0;
	}

	double* s = SG_CALLOC(double, n_feats*n_tasks);
	double* g = SG_CALLOC(double, n_feats*n_tasks);
	double* v = SG_CALLOC(double, n_feats*n_tasks);

	double* Aw = SG_CALLOC(double, n_vecs);
	for (t=0; t<n_tasks; t++)
	{
		int task_ind_start = options.ind[t];
		int task_ind_end = options.ind[t+1];
		for (i=task_ind_start; i<task_ind_end; i++)
			Aw[i] = features->dense_dot(i,w.matrix+t*n_feats,n_feats);
	}
	double* Av = SG_MALLOC(double, n_vecs);
	double* As = SG_MALLOC(double, n_vecs);
	double* ATAs = SG_MALLOC(double, n_feats*n_tasks);
	double* resid = SG_MALLOC(double, n_vecs*n_tasks);

	double L = 1.0;

	double* wp = SG_CALLOC(double, n_feats*n_tasks);
	for (i=0; i<n_feats*n_tasks; i++)
		wp[i] = w[i];
	double* Awp = SG_MALLOC(double, n_vecs);
	for (i=0; i<n_vecs; i++)
		Awp[i] = Aw[i];
	double* wwp = SG_CALLOC(double, n_feats*n_tasks);

	double* w_row = SG_MALLOC(double, n_tasks);

	double alphap = 0.0;
	double alpha = 1.0;

	while (!done && iter <= options.max_iter)
	{
		beta = (alphap-1.0)/alpha;

		for (i=0; i<n_feats*n_tasks; i++)
			s[i] = w[i] + beta*wwp[i];

		for (i=0; i<n_vecs; i++)
			As[i] = Aw[i] + beta*(Aw[i]-Awp[i]);

		// ATAs = A'*As
		for (i=0; i<n_feats*n_tasks; i++)
			ATAs[i] = 0.0;

		for (t=0; t<n_tasks; t++)
		{
			int task_ind_start = options.ind[t];
			int task_ind_end = options.ind[t+1];
			for (i=task_ind_start; i<task_ind_end; i++)
				features->add_to_dense_vec(As[i],i,ATAs+t*n_feats,n_feats);
		}

		// g = ATAs - ATy
		for (i=0; i<n_feats*n_tasks; i++)
			g[i] = ATAs[i] - ATy[i];

		for (i=0; i<n_feats*n_tasks; i++)
			wp[i] = w[i];

		for (i=0; i<n_vecs; i++)
			Awp[i] = Aw[i];

		while (true)
		{
			// v = s - g / L
			for (i=0; i<n_feats*n_tasks; i++)
				v[i] = s[i] - g[i]*(1.0/L);

			if (options.general)
				general_altra_mt(w.matrix, v, n_feats, n_tasks, options.G, options.ind_t, options.n_nodes, lambda/L);
			else
				altra_mt(w.matrix, v, n_feats, n_tasks, options.ind_t, options.n_nodes, lambda/L);

			// v = x - s
			for (i=0; i<n_feats*n_tasks; i++)
				v[i] = w[i] - s[i];

			for (t=0; t<n_tasks; t++)
			{
				int task_ind_start = options.ind[t];
				int task_ind_end = options.ind[t+1];
				for (i=task_ind_start; i<task_ind_end; i++)
					Aw[i] = features->dense_dot(i,w.matrix+t*n_feats,n_feats);
			}

			for (i=0; i<n_vecs; i++)
				Av[i] = Aw[i] - As[i];

			// squared frobenius norm of r
			double r_sum = SGVector<float64_t>::dot(v,v,n_feats*n_tasks);

			double l_sum = SGVector<float64_t>::dot(Av,Av,n_vecs);

			if (r_sum <= 1e-20)
			{
				gradient_break = true;
				break;
			}

			if (l_sum <= r_sum*L)
				break;
			else
				L = CMath::max(2*L, l_sum/r_sum);
		}

		alphap = alpha;
		alpha = 0.5*(1+CMath::sqrt(4*alpha*alpha+1));

		for (i=0; i<n_feats*n_tasks; i++)
			wwp[i] = w[i] - wp[i];

		// Aw - y
		for (i=0; i<n_vecs; i++)
			resid[i] = Aw[i] - y[i];

		double tree_norm = 0.0;
		for (i=0; i<n_feats; i++)
		{
			for (j=0; j<n_tasks; j++)
				w_row[j] = w(i,j);

			if (options.general)
				tree_norm += general_treeNorm(w_row,n_tasks,options.G,
											 options.ind_t,options.n_nodes);
			else
				tree_norm += treeNorm(w_row,n_tasks,options.ind_t,options.n_nodes);
		}

		funcp = func;
		func = 0.5*SGVector<float64_t>::dot(resid,resid,n_vecs) + lambda*tree_norm;

		if (gradient_break)
			break;

		double norm_wp, norm_wwp;
		double step;
		switch (options.termination)
		{
			case 0:
				if (iter>=2)
				{
					step = CMath::abs(func-funcp);

					if (step <= options.tolerance)
						done = true;
				}
				break;
			case 1:
				if (iter>=2)
				{
					step = CMath::abs(func-funcp);
					if (step <= step*options.tolerance)
						done = true;
				}
				break;
			case 2:
				if (func <= options.tolerance)
					done = true;
				break;
			case 3:
				norm_wwp = CMath::sqrt(SGVector<float64_t>::dot(wwp,wwp,n_feats));
				if (norm_wwp <= options.tolerance)
					done = true;
				break;
			case 4:
				norm_wp = CMath::sqrt(SGVector<float64_t>::dot(wp,wp,n_feats));
				norm_wwp = CMath::sqrt(SGVector<float64_t>::dot(wwp,wwp,n_feats));
				if (norm_wwp <= options.tolerance*CMath::max(norm_wp,1.0))
					done = true;
				break;
			case 5:
				if (iter > options.max_iter)
					done = true;
				break;
			default:
				done = true;
		}

		if (iter%options.restart_num==0)
		{
			alphap = 0.0;
			alpha = 1.0;
			L = 0.5*L;
			for (i=0; i<n_feats; i++)
				wp[i] = w[i];

			for (i=0; i<n_vecs; i++)
				Awp[i] = Aw[i];

			for (i=0; i<n_feats; i++)
				wwp[i] = 0.0;
		}

		iter++;
	}

	SG_FREE(ATy);
	SG_FREE(wp);
	SG_FREE(wwp);
	SG_FREE(s);
	SG_FREE(g);
	SG_FREE(v);
	SG_FREE(Aw);
	SG_FREE(Awp);
	SG_FREE(Av);
	SG_FREE(As);
	SG_FREE(ATAs);
	SG_FREE(resid);
	SG_FREE(w_row);

	return w;
};
};
<|endoftext|>


<commit_before>#include "include/properties_reader.h"

//Constructor
PropertiesReader::PropertiesReader(std::string file_path) {
  //Open the file
  std::string line;

  struct stat buffer;
  if (stat (file_path.c_str(), &buffer) == 0) {

    std::ifstream file (file_path);

    if (file.is_open()) {
      while (getline (file, line) ) {
        //Read a line from the property file

        //Figure out if we have a blank or comment line
        bool keep_going = true;
        if (line.length() > 0) {
          if (line[0] != '/' || line[1] != '/') {
            int eq_pos = line.find("=", 0);
            std::string var_name = line.substr(0, eq_pos);
            std::string var_value = line.substr(eq_pos+1, line.length() - eq_pos);
            opts.emplace(var_name, var_value);
          }
        }
      }
      file.close();
    }
  }
  else
  {
    logging->error("CONFIGURE: Configuration File not found");
    return false;
  }
return true;
}

  //Does a key exist?
bool PropertiesReader::opt_exist( std::string key )
{
  auto search = opts.find(key);
  if (search != opts.end())
  {
    return true;
  }
  return false;
}
<commit_msg>Properties Reader Fixes<commit_after>#include "include/properties_reader.h"

//Constructor
PropertiesReader::PropertiesReader(std::string file_path) {
  //Open the file
  std::string line;

  struct stat buffer;
  if (stat (file_path.c_str(), &buffer) == 0) {

    std::ifstream file (file_path);

    if (file.is_open()) {
      while (getline (file, line) ) {
        //Read a line from the property file

        //Figure out if we have a blank or comment line
        if (line.length() > 0) {
          if (line[0] != '/' || line[1] != '/') {
            int eq_pos = line.find("=", 0);
            std::string var_name = line.substr(0, eq_pos);
            std::string var_value = line.substr(eq_pos+1, line.length() - eq_pos);
            opts.emplace(var_name, var_value);
          }
        }
      }
      file.close();
    }
  }
}

  //Does a key exist?
bool PropertiesReader::opt_exist( std::string key )
{
  auto search = opts.find(key);
  if (search != opts.end())
  {
    return true;
  }
  return false;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "assert.hpp"
#include "Function.hpp"

#include "mtac/call_graph.hpp"
#include "mtac/Program.hpp"
#include "mtac/Function.hpp"

using namespace eddic;

mtac::call_graph::~call_graph(){
    for(auto& node_key : nodes){
        auto& node = node_key.second;

        for(auto& edge : node->in_edges){
            edge->source = nullptr;
            edge->target = nullptr;
        }

        for(auto& edge : node->out_edges){
            edge->source = nullptr;
            edge->target = nullptr;
        }

        node->in_edges.clear();
        node->out_edges.clear();
    }
}

mtac::call_graph_node_p mtac::call_graph::node(eddic::Function& function){
    auto it = nodes.find(function.mangled_name());

    if(it == nodes.end()){
        auto node = std::make_shared<mtac::call_graph_node>(function);
        nodes[function.mangled_name()] = node;
        return node;
    }

    return it->second;
}

mtac::call_graph_edge_p mtac::call_graph::edge(eddic::Function& source, eddic::Function& target){
    auto source_node = node(source);
    auto target_node = node(target);

    for(auto& edge : source_node->out_edges){
        if(edge->target == target_node){
            return edge;
        }
    }

    return nullptr;
}

void mtac::call_graph::add_edge(eddic::Function& source, eddic::Function& target){
    auto edge = this->edge(source, target);

    if(!edge){
        auto source_node = node(source);
        auto target_node = node(target);

        edge = std::make_shared<mtac::call_graph_edge>(source_node, target_node);

        source_node->out_edges.push_back(edge);
        target_node->in_edges.push_back(edge);
    }

    ++edge->count;
}

void compute_reachable(mtac::Reachable& reachable, mtac::call_graph_node_p node){
    if(reachable.find(node->function) == reachable.end()){
        reachable.insert(node->function);

        for(auto& edge : node->out_edges){
            if(edge->count > 0){
                compute_reachable(reachable, edge->target);
            }
        }
    }
}

void mtac::call_graph::compute_reachable(){
    eddic_assert(entry, "The call graph must be built before computing reachable");

    release_reachable();

    ::compute_reachable(reachable, entry);
}

void mtac::call_graph::release_reachable(){
    reachable.clear();
}

bool mtac::call_graph::is_reachable(eddic::Function& function){
    return reachable.find(function) != reachable.end();
}

void mtac::build_call_graph(mtac::Program& program){
    auto& cg = program.call_graph;

    for(auto& function : program){
        for(auto& block : function){
            for(auto& quadruple : block){
                if(quadruple.op == mtac::Operator::CALL){
                    cg.add_edge(function.definition(), quadruple.function());
                }
            }
        }

        if(function.is_main()){
            cg.entry = cg.node(function.definition());
        }
    }
}
<commit_msg>Time the call graph building<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "assert.hpp"
#include "Function.hpp"
#include "GlobalContext.hpp"

#include "mtac/call_graph.hpp"
#include "mtac/Program.hpp"
#include "mtac/Function.hpp"

using namespace eddic;

mtac::call_graph::~call_graph(){
    for(auto& node_key : nodes){
        auto& node = node_key.second;

        for(auto& edge : node->in_edges){
            edge->source = nullptr;
            edge->target = nullptr;
        }

        for(auto& edge : node->out_edges){
            edge->source = nullptr;
            edge->target = nullptr;
        }

        node->in_edges.clear();
        node->out_edges.clear();
    }
}

mtac::call_graph_node_p mtac::call_graph::node(eddic::Function& function){
    auto it = nodes.find(function.mangled_name());

    if(it == nodes.end()){
        auto node = std::make_shared<mtac::call_graph_node>(function);
        nodes[function.mangled_name()] = node;
        return node;
    }

    return it->second;
}

mtac::call_graph_edge_p mtac::call_graph::edge(eddic::Function& source, eddic::Function& target){
    auto source_node = node(source);
    auto target_node = node(target);

    for(auto& edge : source_node->out_edges){
        if(edge->target == target_node){
            return edge;
        }
    }

    return nullptr;
}

void mtac::call_graph::add_edge(eddic::Function& source, eddic::Function& target){
    auto edge = this->edge(source, target);

    if(!edge){
        auto source_node = node(source);
        auto target_node = node(target);

        edge = std::make_shared<mtac::call_graph_edge>(source_node, target_node);

        source_node->out_edges.push_back(edge);
        target_node->in_edges.push_back(edge);
    }

    ++edge->count;
}

void compute_reachable(mtac::Reachable& reachable, mtac::call_graph_node_p node){
    if(reachable.find(node->function) == reachable.end()){
        reachable.insert(node->function);

        for(auto& edge : node->out_edges){
            if(edge->count > 0){
                compute_reachable(reachable, edge->target);
            }
        }
    }
}

void mtac::call_graph::compute_reachable(){
    eddic_assert(entry, "The call graph must be built before computing reachable");

    release_reachable();

    ::compute_reachable(reachable, entry);
}

void mtac::call_graph::release_reachable(){
    reachable.clear();
}

bool mtac::call_graph::is_reachable(eddic::Function& function){
    return reachable.find(function) != reachable.end();
}

void mtac::build_call_graph(mtac::Program& program){
    timing_timer timer(program.context->timing(), "build_cg");

    auto& cg = program.call_graph;

    for(auto& function : program){
        for(auto& block : function){
            for(auto& quadruple : block){
                if(quadruple.op == mtac::Operator::CALL){
                    cg.add_edge(function.definition(), quadruple.function());
                }
            }
        }

        if(function.is_main()){
            cg.entry = cg.node(function.definition());
        }
    }
}
<|endoftext|>