<commit_before>/*
 * Copyright (c) 2016 gencache authors
 * This file is released under the MIT License
 * http://opensource.org/licenses/MIT
 */

#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <dirent.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>

#include "json.hpp"

using json = nlohmann::json;

json parse_dir_recursive(const std::string& path, const int depth) {
	DIR *dir;
	struct dirent *dent;
	json r;

	/* do not recurse any further */
	if(depth == 0)
		return r;

	dir = opendir(path.c_str());
	if(dir != nullptr) {
		while((dent = readdir(dir)) != nullptr) {
			std::string dirname = std::string(dent->d_name);
			/* unicode aware lowercase conversion */
			std::string lower_dirname;
			icu::UnicodeString(dent->d_name).toLower().toUTF8String(lower_dirname);

			/* dig deeper, but skip upper and current directory */
			if(dent->d_type == DT_DIR && dirname != ".." && dirname != ".") {
				json temp = parse_dir_recursive(path + "/" + dirname, depth - 1);
				if (!temp.empty())
					r[lower_dirname] = temp;
			}

			/* add files */
			if(dent->d_type == DT_REG || dent->d_type == DT_LNK)
				r[lower_dirname] = dirname;
		}
	}
	closedir(dir);

	return r;
}

int main(int argc, const char* argv[]) {
	struct stat path_info;

	/* defaults */
	int recursion_depth = 3;
	bool pretty_print = false;
	std::string path = ".";
	std::string output = "index.json";

	/* parse command line arguments */
	for (int i = 1; i < argc; ++i) {
		std::string arg = argv[i];

		if ((arg == "--help") || (arg == "-h")) {
			std::cout << "gencache - JSON cache generator for EasyRPG Player ports" << std::endl << std::endl;
			std::cout << "Usage: gencache [ Options ] [ Directory ]" << std::endl;
			std::cout << "Options:" << std::endl;
			std::cout << "  -h, --help             This usage message" << std::endl;
			std::cout << "  -p, --pretty           Pretty print the JSON contents" << std::endl;
			std::cout << "  -o, --output <file>    Output file name (default: \"" << output << "\")" << std::endl;
			std::cout << "  -r, --recurse <depth>  Recursion depth (default: " << std::to_string(recursion_depth) << ")" << std::endl << std::endl;
			std::cout << "It uses the current directory if not given as argument." << std::endl;
			return 0;
		} else if((arg == "--pretty") || (arg == "-p")) {
			pretty_print = true;
		} else if((arg == "--output") || (arg == "-o")) {
			if (i + 1 < argc) {
				output = argv[++i];
			} else {
				std::cerr << "--output without file name argument" << std::endl;
				return 1;
			}
		} else if((arg == "--recurse") || (arg == "-r")) {
			if (i + 1 < argc) {
				std::istringstream iss(argv[++i]);
				if (!(iss >> recursion_depth)) {
					std::cerr << "--recurse option needs a number argument" << std::endl;
					return 1;
				}
			} else {
				std::cerr << "--recurse without depth argument" << std::endl;
				return 1;
			}
		} else {
			if (path == ".") {
				if(stat(arg.c_str(), &path_info) != 0) {
					std::cerr << "Cannot access directory: \"" << arg << "\"" << std::endl;
					return 1;
				} else if(!(path_info.st_mode & S_IFDIR)) {
					std::cerr << "Not a directory: \"" << arg << "\"" << std::endl;
					return 1;
				} else {
					path = arg;
				}
			} else {
				std::cerr << "Skipping additional argument: \"" << arg << "\"..." << std::endl;
			}
		}
	}

	/* get directory contents */
	json cache = parse_dir_recursive(path, recursion_depth);

	/* write to cache file */
	std::ofstream cache_file;
	cache_file.open(output);
	cache_file << cache.dump(pretty_print ? 2 : -1);
	cache_file.close();
	std::cout << "JSON cache has been written to \"" << output << "\"." << std::endl;

	return 0;
}
<commit_msg>Add legacy json mode This should work with current Player Emscripten port.<commit_after>/*
 * Copyright (c) 2016 gencache authors
 * This file is released under the MIT License
 * http://opensource.org/licenses/MIT
 */

#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <dirent.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>

#include "json.hpp"

/* legacy mode, linear list */
#define LEGACY 1

using json = nlohmann::json;

json parse_dir_recursive(const std::string& path, const int depth) {
	DIR *dir;
	struct dirent *dent;
	json r;

	/* do not recurse any further */
	if(depth == 0)
		return r;

	dir = opendir(path.c_str());
	if(dir != nullptr) {
		while((dent = readdir(dir)) != nullptr) {
			std::string dirname = std::string(dent->d_name);
			/* unicode aware lowercase conversion */
			std::string lower_dirname;
			icu::UnicodeString(dent->d_name).toLower().toUTF8String(lower_dirname);

			/* dig deeper, but skip upper and current directory */
			if(dent->d_type == DT_DIR && dirname != ".." && dirname != ".") {
				json temp = parse_dir_recursive(path + "/" + dirname, depth - 1);
				if (!temp.empty()) {
#if LEGACY
					for (json::iterator it = temp.begin(); it != temp.end(); ++it) {
						std::string val = it.value();
						std::string key = it.key();
						r[lower_dirname + "/" + key.substr(0, key.find_last_of("."))] = dirname + "/" + val;
					}
#else
					r[lower_dirname] = temp;
#endif
				}
			}

			/* add files */
			if(dent->d_type == DT_REG || dent->d_type == DT_LNK)
				r[lower_dirname] = dirname;
		}
	}
	closedir(dir);

	return r;
}

int main(int argc, const char* argv[]) {
	struct stat path_info;

	/* defaults */
	int recursion_depth = 3;
	bool pretty_print = false;
	std::string path = ".";
	std::string output = "index.json";

	/* parse command line arguments */
	for (int i = 1; i < argc; ++i) {
		std::string arg = argv[i];

		if ((arg == "--help") || (arg == "-h")) {
			std::cout << "gencache - JSON cache generator for EasyRPG Player ports" << std::endl << std::endl;
			std::cout << "Usage: gencache [ Options ] [ Directory ]" << std::endl;
			std::cout << "Options:" << std::endl;
			std::cout << "  -h, --help             This usage message" << std::endl;
			std::cout << "  -p, --pretty           Pretty print the JSON contents" << std::endl;
			std::cout << "  -o, --output <file>    Output file name (default: \"" << output << "\")" << std::endl;
			std::cout << "  -r, --recurse <depth>  Recursion depth (default: " << std::to_string(recursion_depth) << ")" << std::endl << std::endl;
			std::cout << "It uses the current directory if not given as argument." << std::endl;
			return 0;
		} else if((arg == "--pretty") || (arg == "-p")) {
			pretty_print = true;
		} else if((arg == "--output") || (arg == "-o")) {
			if (i + 1 < argc) {
				output = argv[++i];
			} else {
				std::cerr << "--output without file name argument" << std::endl;
				return 1;
			}
		} else if((arg == "--recurse") || (arg == "-r")) {
			if (i + 1 < argc) {
				std::istringstream iss(argv[++i]);
				if (!(iss >> recursion_depth)) {
					std::cerr << "--recurse option needs a number argument" << std::endl;
					return 1;
				}
			} else {
				std::cerr << "--recurse without depth argument" << std::endl;
				return 1;
			}
		} else {
			if (path == ".") {
				if(stat(arg.c_str(), &path_info) != 0) {
					std::cerr << "Cannot access directory: \"" << arg << "\"" << std::endl;
					return 1;
				} else if(!(path_info.st_mode & S_IFDIR)) {
					std::cerr << "Not a directory: \"" << arg << "\"" << std::endl;
					return 1;
				} else {
					path = arg;
				}
			} else {
				std::cerr << "Skipping additional argument: \"" << arg << "\"..." << std::endl;
			}
		}
	}

	/* get directory contents */
	json cache = parse_dir_recursive(path, recursion_depth);

	/* write to cache file */
	std::ofstream cache_file;
	cache_file.open(output);
	cache_file << cache.dump(pretty_print ? 2 : -1);
	cache_file.close();
	std::cout << "JSON cache has been written to \"" << output << "\"." << std::endl;

	return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include "geometry/point2d.hpp"
#include "geometry/rect2d.hpp"
#include "geometry/distance.hpp"

#include "base/math.hpp"

#include "std/vector.hpp"
#include "std/algorithm.hpp"
#include "std/type_traits.hpp"

namespace m2
{
  namespace detail
  {
    struct DefEqualFloat
    {
      template <class TPoint>
      bool EqualPoints(TPoint const & p1, TPoint const & p2) const
      {
        return my::AlmostEqualAbs(p1.x, p2.x, static_cast<typename TPoint::value_type>(1e-7)) &&
               my::AlmostEqualAbs(p1.y, p2.y, static_cast<typename TPoint::value_type>(1e-7));
      }
      template <class TCoord>
      bool EqualZero(TCoord val, TCoord exp) const
      {
        return my::AlmostEqualAbs(val, 0.0, exp);
      }
    };

    struct DefEqualInt
    {
      template <class TPoint>
      bool EqualPoints(TPoint const & p1, TPoint const & p2) const
      {
        return p1 == p2;
      }
      template <class TCoord>
      bool EqualZero(TCoord val, TCoord) const
      {
        return val == 0;
      }
    };

    template <int floating> struct TraitsType;
    template <> struct TraitsType<1>
    {
      typedef DefEqualFloat EqualType;
      typedef double BigType;
    };
    template <> struct TraitsType<0>
    {
      typedef DefEqualInt EqualType;
      typedef int64_t BigType;
    };
  }

  template <class PointT>
  class Region
  {
    template <class TArchive, class TPoint>
    friend TArchive & operator << (TArchive & ar, Region<TPoint> const & region);
    template <class TArchive, class TPoint>
    friend TArchive & operator >> (TArchive & ar, Region<TPoint> & region);

  public:
    typedef PointT ValueT;
    typedef typename PointT::value_type CoordT;

  private:
    typedef vector<PointT> ContainerT;
    typedef detail::TraitsType<is_floating_point<CoordT>::value> TraitsT;

  public:
    /// @name Needed for boost region concept.
    //@{
    typedef typename ContainerT::const_iterator IteratorT;
    IteratorT Begin() const { return m_points.begin(); }
    IteratorT End() const { return m_points.end(); }
    size_t Size() const { return m_points.size(); }
    //@}

  public:
    Region() = default;

    explicit Region(vector<PointD> && points) : m_points(move(points))
    {
      CalcLimitRect();
    }

    template <class IterT>
    Region(IterT first, IterT last) : m_points(first, last)
    {
      CalcLimitRect();
    }

    template <class IterT>
    void Assign(IterT first, IterT last)
    {
      m_points.assign(first, last);
      CalcLimitRect();
    }

    template <class IterT, class Fn>
    void AssignEx(IterT first, IterT last, Fn fn)
    {
      m_points.reserve(distance(first, last));

      while (first != last)
        m_points.push_back(fn(*first++));

      CalcLimitRect();
    }

    void AddPoint(PointT const & pt)
    {
      m_points.push_back(pt);
      m_rect.Add(pt);
    }

    template <class TFunctor>
    void ForEachPoint(TFunctor toDo) const
    {
      for_each(m_points.begin(), m_points.end(), toDo);
    }

    inline m2::Rect<CoordT> const & GetRect() const { return m_rect; }
    inline size_t GetPointsCount() const { return m_points.size(); }
    inline bool IsValid() const { return GetPointsCount() > 2; }

    void Swap(Region<PointT> & rhs)
    {
      m_points.swap(rhs.m_points);
      std::swap(m_rect, rhs.m_rect);
    }

    ContainerT Data() const { return m_points; }

    inline bool IsIntersect(CoordT const & x11, CoordT const & y11, CoordT const & x12, CoordT const & y12,
                             CoordT const & x21, CoordT const & y21, CoordT const & x22, CoordT const & y22, PointT & pt) const
    {
      if (!((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22-y21)))
        return false;
      double v = ((x12 - x11) * (y21 - y11) + (y12 - y11) * (x11 - x21)) / ((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22 - y21));
      PointT p(x21 + (x22 - x21) * v, y21 + (y22 - y21) * v);

      if (!(((p.x >= x11) && (p.x <= x12)) || ((p.x <= x11) && (p.x >= x12))))
        return false;
      if (!(((p.x >= x21) && (p.x <= x22)) || ((p.x <= x21) && (p.x >= x22))))
        return false;
      if (!(((p.y >= y11) && (p.y <= y12)) || ((p.y <= y11) && (p.y >= y12))))
        return false;
      if (!(((p.y >= y21) && (p.y <= y22)) || ((p.y <= y21) && (p.y >= y22))))
        return false;

      pt = p;
      return true;
    }

    inline bool IsIntersect(PointT const & p1, PointT const & p2, PointT const & p3, PointT const & p4 , PointT & pt) const
    {
      return IsIntersect(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, pt);
    }

  public:

    /// Taken from Computational Geometry in C and modified
    template <class EqualF>
    bool Contains(PointT const & pt, EqualF equalF) const
    {
      if (!m_rect.IsPointInside(pt))
        return false;

      int rCross = 0; /* number of right edge/ray crossings */
      int lCross = 0; /* number of left edge/ray crossings */

      size_t const numPoints = m_points.size();

      typedef typename TraitsT::BigType BigCoordT;
      typedef Point<BigCoordT> BigPointT;

      BigPointT prev = BigPointT(m_points[numPoints - 1]) - BigPointT(pt);
      for (size_t i = 0; i < numPoints; ++i)
      {
        if (equalF.EqualPoints(m_points[i], pt))
          return true;

        BigPointT const curr = BigPointT(m_points[i]) - BigPointT(pt);

        bool const rCheck = ((curr.y > 0) != (prev.y > 0));
        bool const lCheck = ((curr.y < 0) != (prev.y < 0));

        if (rCheck || lCheck)
        {
          ASSERT_NOT_EQUAL ( curr.y, prev.y, () );

          BigCoordT const delta = prev.y - curr.y;
          BigCoordT const cp = CrossProduct(curr, prev);

          if (!equalF.EqualZero(cp, delta))
          {
            bool const PrevGreaterCurr = delta > 0.0;

            if (rCheck && ((cp > 0) == PrevGreaterCurr)) ++rCross;
            if (lCheck && ((cp > 0) != PrevGreaterCurr)) ++lCross;
          }
        }

        prev = curr;
      }

      /* q on the edge if left and right cross are not the same parity. */
      if ((rCross & 1) != (lCross & 1))
        return true;  // on the edge

      /* q inside if an odd number of crossings. */
      if (rCross & 1)
        return true;  // inside
      else
        return false; // outside
    }

    bool Contains(PointT const & pt) const
    {
      return Contains(pt, typename TraitsT::EqualType());
    }

    /// Finds point of intersection with the section.
    bool FindIntersection(PointT const & point1, PointT const & point2, PointT & result) const
    {
      if (m_points.empty())
        return false;
      PointT const * prev = &m_points.back();
      for (PointT const & curr : m_points)
      {
        if (IsIntersect(point1, point2, *prev, curr, result))
          return true;
        prev = &curr;
      }
      return false;
    }

    /// Slow check that point lies at the border.
    template <class EqualF>
    bool AtBorder(PointT const & pt, double const delta, EqualF equalF) const
    {
      if (!m_rect.IsPointInside(pt))
        return false;

      const double squareDelta = delta*delta;
      size_t const numPoints = m_points.size();

      PointT prev = m_points[numPoints - 1];
      DistanceToLineSquare<PointT> distance;
      for (size_t i = 0; i < numPoints; ++i)
      {
        PointT const curr = m_points[i];

        // Borders often have same points with ways
        if (equalF.EqualPoints(m_points[i], pt))
          return true;

        distance.SetBounds(prev, curr);
        if (distance(pt) < squareDelta)
          return true;

        prev = curr;
      }

      return false; // Point lies outside the border.
    }

    bool AtBorder(PointT const & pt, double const delta) const
    {
      return AtBorder(pt, delta, typename TraitsT::EqualType());
    }

  private:
    void CalcLimitRect()
    {
      m_rect.MakeEmpty();
      for (size_t i = 0; i < m_points.size(); ++i)
        m_rect.Add(m_points[i]);
    }

    ContainerT m_points;
    m2::Rect<CoordT> m_rect;

    template <class T> friend string DebugPrint(Region<T> const &);
  };

  template <class PointT>
  void swap(Region<PointT> & r1, Region<PointT> & r2)
  {
    r1.Swap(r2);
  }

  template <class TArchive, class PointT>
  TArchive & operator >> (TArchive & ar, Region<PointT> & region)
  {
    ar >> region.m_rect;
    ar >> region.m_points;
    return ar;
  }

  template <class TArchive, class PointT>
  TArchive & operator << (TArchive & ar, Region<PointT> const & region)
  {
    ar << region.m_rect;
    ar << region.m_points;
    return ar;
  }

  template <class PointT>
  inline string DebugPrint(Region<PointT> const & r)
  {
    return (DebugPrint(r.m_rect) + ::DebugPrint(r.m_points));
  }

  typedef Region<m2::PointD> RegionD;
  typedef Region<m2::PointI> RegionI;
  typedef Region<m2::PointU> RegionU;
}
<commit_msg>Fix problem with incorrect results of contains<commit_after>#pragma once

#include "geometry/point2d.hpp"
#include "geometry/rect2d.hpp"
#include "geometry/distance.hpp"

#include "base/math.hpp"

#include "std/vector.hpp"
#include "std/algorithm.hpp"
#include "std/type_traits.hpp"

namespace m2
{
  namespace detail
  {
    struct DefEqualFloat
    {
      // 10e-9 is two orders of magnitude more accurate than our OSM source data.
      static double constexpr kPrecision = 10e-9;
      template <class TPoint>
      bool EqualPoints(TPoint const & p1, TPoint const & p2) const
      {
        return my::AlmostEqualAbs(p1.x, p2.x, static_cast<typename TPoint::value_type>(kPrecision)) &&
               my::AlmostEqualAbs(p1.y, p2.y, static_cast<typename TPoint::value_type>(kPrecision));
      }
      template <class TCoord>
      bool EqualZero(TCoord val, TCoord) const
      {
        return my::AlmostEqualAbs(val, 0.0, static_cast<TCoord>(kPrecision));
      }
    };

    struct DefEqualInt
    {
      template <class TPoint>
      bool EqualPoints(TPoint const & p1, TPoint const & p2) const
      {
        return p1 == p2;
      }
      template <class TCoord>
      bool EqualZero(TCoord val, TCoord) const
      {
        return val == 0;
      }
    };

    template <int floating> struct TraitsType;
    template <> struct TraitsType<1>
    {
      typedef DefEqualFloat EqualType;
      typedef double BigType;
    };
    template <> struct TraitsType<0>
    {
      typedef DefEqualInt EqualType;
      typedef int64_t BigType;
    };
  }

  template <class PointT>
  class Region
  {
    template <class TArchive, class TPoint>
    friend TArchive & operator << (TArchive & ar, Region<TPoint> const & region);
    template <class TArchive, class TPoint>
    friend TArchive & operator >> (TArchive & ar, Region<TPoint> & region);

  public:
    typedef PointT ValueT;
    typedef typename PointT::value_type CoordT;

  private:
    typedef vector<PointT> ContainerT;
    typedef detail::TraitsType<is_floating_point<CoordT>::value> TraitsT;

  public:
    /// @name Needed for boost region concept.
    //@{
    typedef typename ContainerT::const_iterator IteratorT;
    IteratorT Begin() const { return m_points.begin(); }
    IteratorT End() const { return m_points.end(); }
    size_t Size() const { return m_points.size(); }
    //@}

  public:
    Region() = default;

    explicit Region(vector<PointD> && points) : m_points(move(points))
    {
      CalcLimitRect();
    }

    template <class IterT>
    Region(IterT first, IterT last) : m_points(first, last)
    {
      CalcLimitRect();
    }

    template <class IterT>
    void Assign(IterT first, IterT last)
    {
      m_points.assign(first, last);
      CalcLimitRect();
    }

    template <class IterT, class Fn>
    void AssignEx(IterT first, IterT last, Fn fn)
    {
      m_points.reserve(distance(first, last));

      while (first != last)
        m_points.push_back(fn(*first++));

      CalcLimitRect();
    }

    void AddPoint(PointT const & pt)
    {
      m_points.push_back(pt);
      m_rect.Add(pt);
    }

    template <class TFunctor>
    void ForEachPoint(TFunctor toDo) const
    {
      for_each(m_points.begin(), m_points.end(), toDo);
    }

    inline m2::Rect<CoordT> const & GetRect() const { return m_rect; }
    inline size_t GetPointsCount() const { return m_points.size(); }
    inline bool IsValid() const { return GetPointsCount() > 2; }

    void Swap(Region<PointT> & rhs)
    {
      m_points.swap(rhs.m_points);
      std::swap(m_rect, rhs.m_rect);
    }

    ContainerT Data() const { return m_points; }

    inline bool IsIntersect(CoordT const & x11, CoordT const & y11, CoordT const & x12, CoordT const & y12,
                             CoordT const & x21, CoordT const & y21, CoordT const & x22, CoordT const & y22, PointT & pt) const
    {
      if (!((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22-y21)))
        return false;
      double v = ((x12 - x11) * (y21 - y11) + (y12 - y11) * (x11 - x21)) / ((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22 - y21));
      PointT p(x21 + (x22 - x21) * v, y21 + (y22 - y21) * v);

      if (!(((p.x >= x11) && (p.x <= x12)) || ((p.x <= x11) && (p.x >= x12))))
        return false;
      if (!(((p.x >= x21) && (p.x <= x22)) || ((p.x <= x21) && (p.x >= x22))))
        return false;
      if (!(((p.y >= y11) && (p.y <= y12)) || ((p.y <= y11) && (p.y >= y12))))
        return false;
      if (!(((p.y >= y21) && (p.y <= y22)) || ((p.y <= y21) && (p.y >= y22))))
        return false;

      pt = p;
      return true;
    }

    inline bool IsIntersect(PointT const & p1, PointT const & p2, PointT const & p3, PointT const & p4 , PointT & pt) const
    {
      return IsIntersect(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, pt);
    }

  public:

    /// Taken from Computational Geometry in C and modified
    template <class EqualF>
    bool Contains(PointT const & pt, EqualF equalF) const
    {
      if (!m_rect.IsPointInside(pt))
        return false;

      int rCross = 0; /* number of right edge/ray crossings */
      int lCross = 0; /* number of left edge/ray crossings */

      size_t const numPoints = m_points.size();

      typedef typename TraitsT::BigType BigCoordT;
      typedef Point<BigCoordT> BigPointT;

      BigPointT prev = BigPointT(m_points[numPoints - 1]) - BigPointT(pt);
      for (size_t i = 0; i < numPoints; ++i)
      {
        if (equalF.EqualPoints(m_points[i], pt))
          return true;

        BigPointT const curr = BigPointT(m_points[i]) - BigPointT(pt);

        bool const rCheck = ((curr.y > 0) != (prev.y > 0));
        bool const lCheck = ((curr.y < 0) != (prev.y < 0));

        if (rCheck || lCheck)
        {
          ASSERT_NOT_EQUAL ( curr.y, prev.y, () );

          BigCoordT const delta = prev.y - curr.y;
          BigCoordT const cp = CrossProduct(curr, prev);

          if (!equalF.EqualZero(cp, delta))
          {
            bool const PrevGreaterCurr = delta > 0.0;

            if (rCheck && ((cp > 0) == PrevGreaterCurr)) ++rCross;
            if (lCheck && ((cp > 0) != PrevGreaterCurr)) ++lCross;
          }
        }

        prev = curr;
      }

      /* q on the edge if left and right cross are not the same parity. */
      if ((rCross & 1) != (lCross & 1))
        return true;  // on the edge

      /* q inside if an odd number of crossings. */
      if (rCross & 1)
        return true;  // inside
      else
        return false; // outside
    }

    bool Contains(PointT const & pt) const
    {
      return Contains(pt, typename TraitsT::EqualType());
    }

    /// Finds point of intersection with the section.
    bool FindIntersection(PointT const & point1, PointT const & point2, PointT & result) const
    {
      if (m_points.empty())
        return false;
      PointT const * prev = &m_points.back();
      for (PointT const & curr : m_points)
      {
        if (IsIntersect(point1, point2, *prev, curr, result))
          return true;
        prev = &curr;
      }
      return false;
    }

    /// Slow check that point lies at the border.
    template <class EqualF>
    bool AtBorder(PointT const & pt, double const delta, EqualF equalF) const
    {
      if (!m_rect.IsPointInside(pt))
        return false;

      const double squareDelta = delta*delta;
      size_t const numPoints = m_points.size();

      PointT prev = m_points[numPoints - 1];
      DistanceToLineSquare<PointT> distance;
      for (size_t i = 0; i < numPoints; ++i)
      {
        PointT const curr = m_points[i];

        // Borders often have same points with ways
        if (equalF.EqualPoints(m_points[i], pt))
          return true;

        distance.SetBounds(prev, curr);
        if (distance(pt) < squareDelta)
          return true;

        prev = curr;
      }

      return false; // Point lies outside the border.
    }

    bool AtBorder(PointT const & pt, double const delta) const
    {
      return AtBorder(pt, delta, typename TraitsT::EqualType());
    }

  private:
    void CalcLimitRect()
    {
      m_rect.MakeEmpty();
      for (size_t i = 0; i < m_points.size(); ++i)
        m_rect.Add(m_points[i]);
    }

    ContainerT m_points;
    m2::Rect<CoordT> m_rect;

    template <class T> friend string DebugPrint(Region<T> const &);
  };

  template <class PointT>
  void swap(Region<PointT> & r1, Region<PointT> & r2)
  {
    r1.Swap(r2);
  }

  template <class TArchive, class PointT>
  TArchive & operator >> (TArchive & ar, Region<PointT> & region)
  {
    ar >> region.m_rect;
    ar >> region.m_points;
    return ar;
  }

  template <class TArchive, class PointT>
  TArchive & operator << (TArchive & ar, Region<PointT> const & region)
  {
    ar << region.m_rect;
    ar << region.m_points;
    return ar;
  }

  template <class PointT>
  inline string DebugPrint(Region<PointT> const & r)
  {
    return (DebugPrint(r.m_rect) + ::DebugPrint(r.m_points));
  }

  typedef Region<m2::PointD> RegionD;
  typedef Region<m2::PointI> RegionI;
  typedef Region<m2::PointU> RegionU;
}
<|endoftext|>


<commit_before>/*
 * GLSLShader.cpp
 *
 * Copyright (C) 2006 by Universitaet Stuttgart (VIS). Alle Rechte vorbehalten.
 */

#ifdef _WIN32
#include <windows.h>
#endif /* _WIN32 */

#include "vislib/GLSLShader.h"

#include "vislib/Array.h"
#include "vislib/glverify.h"
#include "vislib/IllegalParamException.h"
#include "vislib/IllegalStateException.h"
#include "vislib/UnsupportedOperationException.h"

/*
 * vislib::graphics::gl::GLSLShader::IsValidHandle
 */
bool vislib::graphics::gl::GLSLShader::IsValidHandle(GLhandleARB hProg) {
    USES_GL_VERIFY;
    GLint status;

    if (GL_SUCCEEDED(::glGetObjectParameterivARB(hProg,
            GL_OBJECT_DELETE_STATUS_ARB, &status))) {
        return (status != 0);
    } else {
        return false;
    }
}

/*
 * vislib::graphics::gl::GLSLShader::RequiredExtensions
 */
const char * vislib::graphics::gl::GLSLShader::RequiredExtensions(void) {
    return "GL_ARB_shader_objects ";
}

/*
 * vislib::graphics::gl::GLSLShader::FTRANSFORM_VERTEX_SHADER_SRC
 */
const char *vislib::graphics::gl::GLSLShader::FTRANSFORM_VERTEX_SHADER_SRC =
    "void main() { "
    "    gl_Position = ftransform();"
    "}";

/*
 * vislib::graphics::gl::GLSLShader::GLSLShader
 */
vislib::graphics::gl::GLSLShader::GLSLShader(void)
        : AbstractOpenGLShader(), hProgObj(0) {
}

/*
 * vislib::graphics::gl::GLSLShader::~GLSLShader
 */
vislib::graphics::gl::GLSLShader::~GLSLShader(void) {
    this->Release();
}

/*
 * vislib::graphics::gl::GLSLShader::Create
 */
bool vislib::graphics::gl::GLSLShader::Create(const char *vertexShaderSrc,
                                              const char *fragmentShaderSrc) {
    const char *v[] = { vertexShaderSrc };
    const char *f[] = { fragmentShaderSrc };

    return this->Create(v, 1, f, 1);
}

/*
 * vislib::graphics::gl::GLSLShader::Create
 */
bool vislib::graphics::gl::GLSLShader::Create(const char **vertexShaderSrc,
        const SIZE_T cntVertexShaderSrc, const char **fragmentShaderSrc,
        const SIZE_T cntFragmentShaderSrc) {
    USES_GL_VERIFY;
    ASSERT(vertexShaderSrc != NULL);
    ASSERT(fragmentShaderSrc != NULL);

    GLhandleARB hPixelShader;
    GLhandleARB hVertexShader;

    /* Prepare vertex shader. */
    GL_VERIFY_THROW(hVertexShader = ::glCreateShaderObjectARB(
        GL_VERTEX_SHADER_ARB));
    GL_VERIFY_THROW(::glShaderSourceARB(hVertexShader,
        static_cast<GLsizei>(cntVertexShaderSrc), vertexShaderSrc, NULL));
    GL_VERIFY_THROW(::glCompileShaderARB(hVertexShader));
    if (!this->isCompiled(hVertexShader)) {
        throw CompileException(this->getProgramInfoLog(hVertexShader), __FILE__,
            __LINE__);
    }

    /* Prepare pixel shader. */
    GL_VERIFY_THROW(hPixelShader = ::glCreateShaderObjectARB(
        GL_FRAGMENT_SHADER_ARB));
    GL_VERIFY_THROW(::glShaderSourceARB(hPixelShader,
        static_cast<GLsizei>(cntFragmentShaderSrc), fragmentShaderSrc, NULL));
    GL_VERIFY_THROW(::glCompileShaderARB(hPixelShader));
    if (!this->isCompiled(hVertexShader)) {
        throw CompileException(this->getProgramInfoLog(hPixelShader), __FILE__,
            __LINE__);
    }

    /* Assemble program object. */
    GL_VERIFY_THROW(this->hProgObj = ::glCreateProgramObjectARB());
    GL_VERIFY_THROW(::glAttachObjectARB(this->hProgObj, hVertexShader));
    GL_VERIFY_THROW(::glAttachObjectARB(this->hProgObj, hPixelShader));
    GL_VERIFY_THROW(::glLinkProgramARB(this->hProgObj));
    if (!this->isLinked(this->hProgObj)) {
        throw CompileException(this->getProgramInfoLog(this->hProgObj),
            __FILE__, __LINE__);
    }

    return true;
}

/*
 * vislib::graphics::gl::GLSLShader::CreateFromFile
 */
bool vislib::graphics::gl::GLSLShader::CreateFromFile(
        const char *vertexShaderFile, const char *fragmentShaderFile) {
    StringA vertexShaderSrc;
    StringA fragmentShaderSrc;

    if (!this->read(vertexShaderSrc, vertexShaderFile)) {
        return false;
    }

    if (!this->read(fragmentShaderSrc, fragmentShaderFile)) {
        return false;
    }

    return this->Create(vertexShaderSrc, fragmentShaderSrc);
}

/*
 * vislib::graphics::gl::GLSLShader::CreateFromFiles
 */
bool vislib::graphics::gl::GLSLShader::CreateFromFiles(
        const char **vertexShaderFiles, const SIZE_T cntVertexShaderFiles,
        const char **fragmentShaderFiles,
        const SIZE_T cntFragmentShaderFiles) {

    // using arrays for automatic cleanup when a 'read' throws an exception
    Array<StringA> vertexShaderSrcs(cntVertexShaderFiles);
    Array<StringA> fragmentShaderSrcs(cntFragmentShaderFiles);

    for(SIZE_T i = 0; i < cntVertexShaderFiles; i++) {
        if (!this->read(vertexShaderSrcs[i], vertexShaderFiles[i])) {
            return false;
        }
    }

    for(SIZE_T i = 0; i < cntFragmentShaderFiles; i++) {
        if (!this->read(fragmentShaderSrcs[i], fragmentShaderFiles[i])) {
            return false;
        }
    }

    // built up pointer arrays for attributes
    const char **vertexShaderSrcPtrs = new const char*[cntVertexShaderFiles];
    const char **fragmentShaderSrcPtrs = new const char*[cntFragmentShaderFiles];

    try {
        for(SIZE_T i = 0; i < cntVertexShaderFiles; i++) {
            vertexShaderSrcPtrs[i] = vertexShaderSrcs[i].PeekBuffer();
        }
        for(SIZE_T i = 0; i < cntFragmentShaderFiles; i++) {
            fragmentShaderSrcPtrs[i] = fragmentShaderSrcs[i].PeekBuffer();
        }

        bool retval = this->Create(vertexShaderSrcPtrs, cntVertexShaderFiles,
            fragmentShaderSrcPtrs, cntFragmentShaderFiles);

        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;

        return retval;

        // free pointer arrays on exception
    } catch(OpenGLException e) { // catch OpenGLException to avoid truncating
        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;
        throw e;
    } catch(CompileException e) {
        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;
        throw e;
    } catch(Exception e) {
        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;
        throw e;
    } catch(...) {
        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;
        throw Exception("Unknown Exception", __FILE__, __LINE__);
    }

    return false; // should be unreachable code!
}

/*
 * vislib::graphics::gl::GLSLShader::Disable
 */
GLenum vislib::graphics::gl::GLSLShader::Disable(void) {
    USES_GL_VERIFY;
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GL_VERIFY_RETURN(::glUseProgramObjectARB(0));
    GL_VERIFY_RETURN(::glDisable(GL_VERTEX_PROGRAM_ARB));
    GL_VERIFY_RETURN(::glDisable(GL_FRAGMENT_PROGRAM_ARB));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::Enable
 */
GLenum vislib::graphics::gl::GLSLShader::Enable(void) {
    USES_GL_VERIFY;
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GL_VERIFY_RETURN(::glEnable(GL_VERTEX_PROGRAM_ARB));
    GL_VERIFY_RETURN(::glEnable(GL_FRAGMENT_PROGRAM_ARB));
    GL_VERIFY_RETURN(::glUseProgramObjectARB(this->hProgObj));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::ParameterLocation
 */
GLint vislib::graphics::gl::GLSLShader::ParameterLocation(const char *name) const {
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));
    return ::glGetUniformLocationARB(this->hProgObj, name);
}

/*
 * vislib::graphics::gl::GLSLShader::Release
 */
GLenum vislib::graphics::gl::GLSLShader::Release(void) {
    USES_GL_VERIFY;

    if (GLSLShader::IsValidHandle(this->hProgObj)) {
        GL_VERIFY_RETURN(::glDeleteObjectARB(this->hProgObj));
    }

    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
                                                      const float v1) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform1fARB(location, v1));
    return GL_NO_ERROR;

}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const float v1, const float v2) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform2fARB(location, v1, v2));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const float v1, const float v2, const float v3) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform3fARB(location, v1, v2, v3));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const float v1, const float v2, const float v3, const float v4) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform4fARB(location, v1, v2, v3, v4));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
                                                      const int v1) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform1iARB(location, v1));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const int v1, const int v2) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform2iARB(location, v1, v2));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const int v1, const int v2, const int v3) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform3iARB(location, v1, v2, v3));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const int v1, const int v2, const int v3, const int v4) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform4iARB(location, v1, v2, v3, v4));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::getProgramInfoLog
 */
vislib::StringA vislib::graphics::gl::GLSLShader::getProgramInfoLog(
        GLhandleARB hProg) {
    USES_GL_VERIFY;
    GLint len = 0;
    GLint written = 0;
    StringA retval;
    char *log = NULL;

    GL_VERIFY_THROW(::glGetObjectParameterivARB(hProg,
        GL_OBJECT_INFO_LOG_LENGTH_ARB, &len));

    if (len > 0) {
        log = retval.AllocateBuffer(len);
        GL_VERIFY_THROW(::glGetInfoLogARB(hProg, len, &written, log));
    }

    return retval;
}

/*
 * vislib::graphics::gl::GLSLShader::isCompiled
 */
bool vislib::graphics::gl::GLSLShader::isCompiled(GLhandleARB hProg) {
    USES_GL_VERIFY;
    GLint status;

    GL_VERIFY_THROW(::glGetObjectParameterivARB(hProg,
        GL_OBJECT_COMPILE_STATUS_ARB, &status));

    return (status != GL_FALSE);
}

/*
 * vislib::graphics::gl::GLSLShader::isLinked
 */
bool vislib::graphics::gl::GLSLShader::isLinked(GLhandleARB hProg) {
    USES_GL_VERIFY;
    GLint status;

    GL_VERIFY_THROW(::glGetObjectParameterivARB(hProg,
        GL_OBJECT_LINK_STATUS_ARB, &status));

    return (status != GL_FALSE);
}
<commit_msg>Tiny bug fixed in GLSLShader<commit_after>/*
 * GLSLShader.cpp
 *
 * Copyright (C) 2006 by Universitaet Stuttgart (VIS). Alle Rechte vorbehalten.
 */

#ifdef _WIN32
#include <windows.h>
#endif /* _WIN32 */

#include "vislib/GLSLShader.h"

#include "vislib/Array.h"
#include "vislib/glverify.h"
#include "vislib/IllegalParamException.h"
#include "vislib/IllegalStateException.h"
#include "vislib/UnsupportedOperationException.h"

/*
 * vislib::graphics::gl::GLSLShader::IsValidHandle
 */
bool vislib::graphics::gl::GLSLShader::IsValidHandle(GLhandleARB hProg) {
    USES_GL_VERIFY;
    GLint status;

    if (GL_SUCCEEDED(::glGetObjectParameterivARB(hProg,
            GL_OBJECT_DELETE_STATUS_ARB, &status))) {
        return (status == 0);
    } else {
        return false;
    }
}

/*
 * vislib::graphics::gl::GLSLShader::RequiredExtensions
 */
const char * vislib::graphics::gl::GLSLShader::RequiredExtensions(void) {
    return "GL_ARB_shader_objects ";
}

/*
 * vislib::graphics::gl::GLSLShader::FTRANSFORM_VERTEX_SHADER_SRC
 */
const char *vislib::graphics::gl::GLSLShader::FTRANSFORM_VERTEX_SHADER_SRC =
    "void main() { "
    "    gl_Position = ftransform();"
    "}";

/*
 * vislib::graphics::gl::GLSLShader::GLSLShader
 */
vislib::graphics::gl::GLSLShader::GLSLShader(void)
        : AbstractOpenGLShader(), hProgObj(0) {
}

/*
 * vislib::graphics::gl::GLSLShader::~GLSLShader
 */
vislib::graphics::gl::GLSLShader::~GLSLShader(void) {
    this->Release();
}

/*
 * vislib::graphics::gl::GLSLShader::Create
 */
bool vislib::graphics::gl::GLSLShader::Create(const char *vertexShaderSrc,
                                              const char *fragmentShaderSrc) {
    const char *v[] = { vertexShaderSrc };
    const char *f[] = { fragmentShaderSrc };

    return this->Create(v, 1, f, 1);
}

/*
 * vislib::graphics::gl::GLSLShader::Create
 */
bool vislib::graphics::gl::GLSLShader::Create(const char **vertexShaderSrc,
        const SIZE_T cntVertexShaderSrc, const char **fragmentShaderSrc,
        const SIZE_T cntFragmentShaderSrc) {
    USES_GL_VERIFY;
    ASSERT(vertexShaderSrc != NULL);
    ASSERT(fragmentShaderSrc != NULL);

    GLhandleARB hPixelShader;
    GLhandleARB hVertexShader;

    /* Prepare vertex shader. */
    GL_VERIFY_THROW(hVertexShader = ::glCreateShaderObjectARB(
        GL_VERTEX_SHADER_ARB));
    GL_VERIFY_THROW(::glShaderSourceARB(hVertexShader,
        static_cast<GLsizei>(cntVertexShaderSrc), vertexShaderSrc, NULL));
    GL_VERIFY_THROW(::glCompileShaderARB(hVertexShader));
    if (!this->isCompiled(hVertexShader)) {
        throw CompileException(this->getProgramInfoLog(hVertexShader), __FILE__,
            __LINE__);
    }

    /* Prepare pixel shader. */
    GL_VERIFY_THROW(hPixelShader = ::glCreateShaderObjectARB(
        GL_FRAGMENT_SHADER_ARB));
    GL_VERIFY_THROW(::glShaderSourceARB(hPixelShader,
        static_cast<GLsizei>(cntFragmentShaderSrc), fragmentShaderSrc, NULL));
    GL_VERIFY_THROW(::glCompileShaderARB(hPixelShader));
    if (!this->isCompiled(hVertexShader)) {
        throw CompileException(this->getProgramInfoLog(hPixelShader), __FILE__,
            __LINE__);
    }

    /* Assemble program object. */
    GL_VERIFY_THROW(this->hProgObj = ::glCreateProgramObjectARB());
    GL_VERIFY_THROW(::glAttachObjectARB(this->hProgObj, hVertexShader));
    GL_VERIFY_THROW(::glAttachObjectARB(this->hProgObj, hPixelShader));
    GL_VERIFY_THROW(::glLinkProgramARB(this->hProgObj));
    if (!this->isLinked(this->hProgObj)) {
        throw CompileException(this->getProgramInfoLog(this->hProgObj),
            __FILE__, __LINE__);
    }

    return true;
}

/*
 * vislib::graphics::gl::GLSLShader::CreateFromFile
 */
bool vislib::graphics::gl::GLSLShader::CreateFromFile(
        const char *vertexShaderFile, const char *fragmentShaderFile) {
    StringA vertexShaderSrc;
    StringA fragmentShaderSrc;

    if (!this->read(vertexShaderSrc, vertexShaderFile)) {
        return false;
    }

    if (!this->read(fragmentShaderSrc, fragmentShaderFile)) {
        return false;
    }

    return this->Create(vertexShaderSrc, fragmentShaderSrc);
}

/*
 * vislib::graphics::gl::GLSLShader::CreateFromFiles
 */
bool vislib::graphics::gl::GLSLShader::CreateFromFiles(
        const char **vertexShaderFiles, const SIZE_T cntVertexShaderFiles,
        const char **fragmentShaderFiles,
        const SIZE_T cntFragmentShaderFiles) {

    // using arrays for automatic cleanup when a 'read' throws an exception
    Array<StringA> vertexShaderSrcs(cntVertexShaderFiles);
    Array<StringA> fragmentShaderSrcs(cntFragmentShaderFiles);

    for(SIZE_T i = 0; i < cntVertexShaderFiles; i++) {
        if (!this->read(vertexShaderSrcs[i], vertexShaderFiles[i])) {
            return false;
        }
    }

    for(SIZE_T i = 0; i < cntFragmentShaderFiles; i++) {
        if (!this->read(fragmentShaderSrcs[i], fragmentShaderFiles[i])) {
            return false;
        }
    }

    // built up pointer arrays for attributes
    const char **vertexShaderSrcPtrs = new const char*[cntVertexShaderFiles];
    const char **fragmentShaderSrcPtrs = new const char*[cntFragmentShaderFiles];

    try {
        for(SIZE_T i = 0; i < cntVertexShaderFiles; i++) {
            vertexShaderSrcPtrs[i] = vertexShaderSrcs[i].PeekBuffer();
        }
        for(SIZE_T i = 0; i < cntFragmentShaderFiles; i++) {
            fragmentShaderSrcPtrs[i] = fragmentShaderSrcs[i].PeekBuffer();
        }

        bool retval = this->Create(vertexShaderSrcPtrs, cntVertexShaderFiles,
            fragmentShaderSrcPtrs, cntFragmentShaderFiles);

        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;

        return retval;

        // free pointer arrays on exception
    } catch(OpenGLException e) { // catch OpenGLException to avoid truncating
        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;
        throw e;
    } catch(CompileException e) {
        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;
        throw e;
    } catch(Exception e) {
        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;
        throw e;
    } catch(...) {
        delete[] vertexShaderSrcPtrs;
        delete[] fragmentShaderSrcPtrs;
        throw Exception("Unknown Exception", __FILE__, __LINE__);
    }

    return false; // should be unreachable code!
}

/*
 * vislib::graphics::gl::GLSLShader::Disable
 */
GLenum vislib::graphics::gl::GLSLShader::Disable(void) {
    USES_GL_VERIFY;
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GL_VERIFY_RETURN(::glUseProgramObjectARB(0));
    GL_VERIFY_RETURN(::glDisable(GL_VERTEX_PROGRAM_ARB));
    GL_VERIFY_RETURN(::glDisable(GL_FRAGMENT_PROGRAM_ARB));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::Enable
 */
GLenum vislib::graphics::gl::GLSLShader::Enable(void) {
    USES_GL_VERIFY;
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GL_VERIFY_RETURN(::glEnable(GL_VERTEX_PROGRAM_ARB));
    GL_VERIFY_RETURN(::glEnable(GL_FRAGMENT_PROGRAM_ARB));
    GL_VERIFY_RETURN(::glUseProgramObjectARB(this->hProgObj));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::ParameterLocation
 */
GLint vislib::graphics::gl::GLSLShader::ParameterLocation(const char *name) const {
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));
    return ::glGetUniformLocationARB(this->hProgObj, name);
}

/*
 * vislib::graphics::gl::GLSLShader::Release
 */
GLenum vislib::graphics::gl::GLSLShader::Release(void) {
    USES_GL_VERIFY;

    if (GLSLShader::IsValidHandle(this->hProgObj)) {
        GL_VERIFY_RETURN(::glDeleteObjectARB(this->hProgObj));
    }

    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
                                                      const float v1) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform1fARB(location, v1));
    return GL_NO_ERROR;

}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const float v1, const float v2) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform2fARB(location, v1, v2));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const float v1, const float v2, const float v3) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform3fARB(location, v1, v2, v3));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const float v1, const float v2, const float v3, const float v4) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform4fARB(location, v1, v2, v3, v4));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
                                                      const int v1) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform1iARB(location, v1));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const int v1, const int v2) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform2iARB(location, v1, v2));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const int v1, const int v2, const int v3) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform3iARB(location, v1, v2, v3));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::SetParameter
 */
GLenum vislib::graphics::gl::GLSLShader::SetParameter(const char *name,
        const int v1, const int v2, const int v3, const int v4) {
    USES_GL_VERIFY;
    ASSERT(name != NULL);
    ASSERT(GLSLShader::IsValidHandle(this->hProgObj));

    GLint location = ::glGetUniformLocationARB(this->hProgObj, name);

    if (location < 0) {
        return GL_INVALID_VALUE;
    }

    GL_VERIFY_RETURN(::glUniform4iARB(location, v1, v2, v3, v4));
    return GL_NO_ERROR;
}

/*
 * vislib::graphics::gl::GLSLShader::getProgramInfoLog
 */
vislib::StringA vislib::graphics::gl::GLSLShader::getProgramInfoLog(
        GLhandleARB hProg) {
    USES_GL_VERIFY;
    GLint len = 0;
    GLint written = 0;
    StringA retval;
    char *log = NULL;

    GL_VERIFY_THROW(::glGetObjectParameterivARB(hProg,
        GL_OBJECT_INFO_LOG_LENGTH_ARB, &len));

    if (len > 0) {
        log = retval.AllocateBuffer(len);
        GL_VERIFY_THROW(::glGetInfoLogARB(hProg, len, &written, log));
    }

    return retval;
}

/*
 * vislib::graphics::gl::GLSLShader::isCompiled
 */
bool vislib::graphics::gl::GLSLShader::isCompiled(GLhandleARB hProg) {
    USES_GL_VERIFY;
    GLint status;

    GL_VERIFY_THROW(::glGetObjectParameterivARB(hProg,
        GL_OBJECT_COMPILE_STATUS_ARB, &status));

    return (status != GL_FALSE);
}

/*
 * vislib::graphics::gl::GLSLShader::isLinked
 */
bool vislib::graphics::gl::GLSLShader::isLinked(GLhandleARB hProg) {
    USES_GL_VERIFY;
    GLint status;

    GL_VERIFY_THROW(::glGetObjectParameterivARB(hProg,
        GL_OBJECT_LINK_STATUS_ARB, &status));

    return (status != GL_FALSE);
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Modified by ScyllaDB
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "utils/serialization.hh"
#include "gms/heart_beat_state.hh"
#include "gms/application_state.hh"
#include "gms/versioned_value.hh"
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <optional>
#include <chrono>

namespace gms {

/**
 * This abstraction represents both the HeartBeatState and the ApplicationState in an EndpointState
 * instance. Any state for a given endpoint can be retrieved from this instance.
 */
class endpoint_state {
public:
    using clk = seastar::lowres_system_clock;
private:
    heart_beat_state _heart_beat_state;
    std::map<application_state, versioned_value> _application_state;
    /* fields below do not get serialized */
    clk::time_point _update_timestamp;
    bool _is_alive;
    bool _is_normal = false;

public:
    bool operator==(const endpoint_state& other) const {
        return _heart_beat_state  == other._heart_beat_state &&
               _application_state == other._application_state &&
               _update_timestamp  == other._update_timestamp &&
               _is_alive          == other._is_alive;
    }

    endpoint_state() noexcept
        : _heart_beat_state(0)
        , _update_timestamp(clk::now())
        , _is_alive(true) {
        update_is_normal();
    }

    endpoint_state(heart_beat_state initial_hb_state) noexcept
        : _heart_beat_state(initial_hb_state)
        , _update_timestamp(clk::now())
        , _is_alive(true) {
        update_is_normal();
    }

    endpoint_state(heart_beat_state&& initial_hb_state,
            const std::map<application_state, versioned_value>& application_state)
        : _heart_beat_state(std::move(initial_hb_state))
        , _application_state(application_state)
        , _update_timestamp(clk::now())
        , _is_alive(true) {
        update_is_normal();
    }

    // Valid only on shard 0
    heart_beat_state& get_heart_beat_state() noexcept {
        return _heart_beat_state;
    }

    // Valid only on shard 0
    const heart_beat_state& get_heart_beat_state() const noexcept {
        return _heart_beat_state;
    }

    void set_heart_beat_state_and_update_timestamp(heart_beat_state hbs) noexcept {
        update_timestamp();
        _heart_beat_state = hbs;
    }

    const versioned_value* get_application_state_ptr(application_state key) const noexcept;

    /**
     * TODO replace this with operations that don't expose private state
     */
    // @Deprecated
    std::map<application_state, versioned_value>& get_application_state_map() noexcept {
        return _application_state;
    }

    const std::map<application_state, versioned_value>& get_application_state_map() const noexcept {
        return _application_state;
    }

    void add_application_state(application_state key, versioned_value value) {
        _application_state[key] = std::move(value);
        update_is_normal();
    }

    void add_application_state(const endpoint_state& es) {
        _application_state = es._application_state;
        update_is_normal();
    }

    /* getters and setters */
    /**
     * @return System.nanoTime() when state was updated last time.
     *
     * Valid only on shard 0.
     */
    clk::time_point get_update_timestamp() const noexcept {
        return _update_timestamp;
    }

    void update_timestamp() noexcept {
        _update_timestamp = clk::now();
    }

    bool is_alive() const noexcept {
        return _is_alive;
    }

    void set_alive(bool alive) noexcept {
        _is_alive = alive;
    }

    void mark_alive() noexcept {
        set_alive(true);
    }

    void mark_dead() noexcept {
        set_alive(false);
    }

    std::string_view get_status() const noexcept {
        constexpr std::string_view empty = "";
        auto* app_state = get_application_state_ptr(application_state::STATUS);
        if (!app_state) {
            return empty;
        }
        const auto& value = app_state->value;
        if (value.empty()) {
            return empty;
        }
        auto pos = value.find(',');
        if (pos == sstring::npos) {
            return std::string_view(value);
        }
        return std::string_view(value.c_str(), pos);
    }

    bool is_shutdown() const {
        return get_status() == sstring(versioned_value::SHUTDOWN);
    }

    bool is_normal() const noexcept {
        return _is_normal;
    }

    void update_is_normal() {
        _is_normal = get_status() == sstring(versioned_value::STATUS_NORMAL);
    }

    bool is_cql_ready() const noexcept;

    friend std::ostream& operator<<(std::ostream& os, const endpoint_state& x);
};

} // gms
<commit_msg>gms/endpoint_state: mark methods using get_status noexcept<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Modified by ScyllaDB
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "utils/serialization.hh"
#include "gms/heart_beat_state.hh"
#include "gms/application_state.hh"
#include "gms/versioned_value.hh"
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <optional>
#include <chrono>

namespace gms {

/**
 * This abstraction represents both the HeartBeatState and the ApplicationState in an EndpointState
 * instance. Any state for a given endpoint can be retrieved from this instance.
 */
class endpoint_state {
public:
    using clk = seastar::lowres_system_clock;
private:
    heart_beat_state _heart_beat_state;
    std::map<application_state, versioned_value> _application_state;
    /* fields below do not get serialized */
    clk::time_point _update_timestamp;
    bool _is_alive;
    bool _is_normal = false;

public:
    bool operator==(const endpoint_state& other) const {
        return _heart_beat_state  == other._heart_beat_state &&
               _application_state == other._application_state &&
               _update_timestamp  == other._update_timestamp &&
               _is_alive          == other._is_alive;
    }

    endpoint_state() noexcept
        : _heart_beat_state(0)
        , _update_timestamp(clk::now())
        , _is_alive(true) {
        update_is_normal();
    }

    endpoint_state(heart_beat_state initial_hb_state) noexcept
        : _heart_beat_state(initial_hb_state)
        , _update_timestamp(clk::now())
        , _is_alive(true) {
        update_is_normal();
    }

    endpoint_state(heart_beat_state&& initial_hb_state,
            const std::map<application_state, versioned_value>& application_state)
        : _heart_beat_state(std::move(initial_hb_state))
        , _application_state(application_state)
        , _update_timestamp(clk::now())
        , _is_alive(true) {
        update_is_normal();
    }

    // Valid only on shard 0
    heart_beat_state& get_heart_beat_state() noexcept {
        return _heart_beat_state;
    }

    // Valid only on shard 0
    const heart_beat_state& get_heart_beat_state() const noexcept {
        return _heart_beat_state;
    }

    void set_heart_beat_state_and_update_timestamp(heart_beat_state hbs) noexcept {
        update_timestamp();
        _heart_beat_state = hbs;
    }

    const versioned_value* get_application_state_ptr(application_state key) const noexcept;

    /**
     * TODO replace this with operations that don't expose private state
     */
    // @Deprecated
    std::map<application_state, versioned_value>& get_application_state_map() noexcept {
        return _application_state;
    }

    const std::map<application_state, versioned_value>& get_application_state_map() const noexcept {
        return _application_state;
    }

    void add_application_state(application_state key, versioned_value value) {
        _application_state[key] = std::move(value);
        update_is_normal();
    }

    void add_application_state(const endpoint_state& es) {
        _application_state = es._application_state;
        update_is_normal();
    }

    /* getters and setters */
    /**
     * @return System.nanoTime() when state was updated last time.
     *
     * Valid only on shard 0.
     */
    clk::time_point get_update_timestamp() const noexcept {
        return _update_timestamp;
    }

    void update_timestamp() noexcept {
        _update_timestamp = clk::now();
    }

    bool is_alive() const noexcept {
        return _is_alive;
    }

    void set_alive(bool alive) noexcept {
        _is_alive = alive;
    }

    void mark_alive() noexcept {
        set_alive(true);
    }

    void mark_dead() noexcept {
        set_alive(false);
    }

    std::string_view get_status() const noexcept {
        constexpr std::string_view empty = "";
        auto* app_state = get_application_state_ptr(application_state::STATUS);
        if (!app_state) {
            return empty;
        }
        const auto& value = app_state->value;
        if (value.empty()) {
            return empty;
        }
        auto pos = value.find(',');
        if (pos == sstring::npos) {
            return std::string_view(value);
        }
        return std::string_view(value.c_str(), pos);
    }

    bool is_shutdown() const noexcept {
        return get_status() == versioned_value::SHUTDOWN;
    }

    bool is_normal() const noexcept {
        return _is_normal;
    }

    void update_is_normal() noexcept {
        _is_normal = get_status() == versioned_value::STATUS_NORMAL;
    }

    bool is_cql_ready() const noexcept;

    friend std::ostream& operator<<(std::ostream& os, const endpoint_state& x);
};

} // gms
<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

    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 or 3 of the License.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "backend.h"
#include "audiooutput.h"
#include "audiodataoutput.h"
#include "audioeffect.h"
#include "mediaobject.h"
#include "videowidget.h"
#include "devicemanager.h"
#include "effectmanager.h"
#include "message.h"
#include "volumefadereffect.h"
#include <gst/interfaces/propertyprobe.h>
#include <phonon/pulsesupport.h>

#include <QtCore/QSet>
#include <QtCore/QVariant>
#include <QtCore/QtPlugin>

QT_BEGIN_NAMESPACE

Q_EXPORT_PLUGIN2(phonon_gstreamer, Phonon::Gstreamer::Backend)

namespace Phonon
{
namespace Gstreamer
{

class MediaNode;

Backend::Backend(QObject *parent, const QVariantList &)
        : QObject(parent)
        , m_deviceManager(0)
        , m_effectManager(0)
        , m_debugLevel(Warning)
        , m_isValid(false)
{
    // Initialise PulseAudio support
    PulseSupport *pulse = PulseSupport::getInstance();
    connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)), SIGNAL(objectDescriptionChanged(ObjectDescriptionType)));

    // In order to support reloading, we only set the app name once...
    static bool first = true;
    if (first) {
        first = false;
        g_set_application_name(qApp->applicationName().toUtf8());
    }
    GError *err = 0;
    bool wasInit = gst_init_check(0, 0, &err);  //init gstreamer: must be called before any gst-related functions
    if (err)
        g_error_free(err);

    qRegisterMetaType<Message>("Message");

    setProperty("identifier",     QLatin1String("phonon_gstreamer"));
    setProperty("backendName",    QLatin1String("Gstreamer"));
    setProperty("backendComment", QLatin1String("Gstreamer plugin for Phonon"));
    setProperty("backendVersion", QLatin1String("0.2"));
    setProperty("backendWebsite", QLatin1String("http://qtsoftware.com/"));

    //check if we should enable debug output
    QString debugLevelString = qgetenv("PHONON_GST_DEBUG");
    int debugLevel = debugLevelString.toInt();
    if (debugLevel > 3) //3 is maximum
        debugLevel = 3;
    m_debugLevel = (DebugLevel)debugLevel;

    if (wasInit) {
        m_isValid = checkDependencies();
        gchar *versionString = gst_version_string();
        logMessage(QString("Using %0").arg(versionString));
        g_free(versionString);
    }
    if (!m_isValid)
        qWarning("Phonon::GStreamer::Backend: Failed to initialize GStreamer");

    m_deviceManager = new DeviceManager(this);
    m_effectManager = new EffectManager(this);
}

Backend::~Backend()
{
    delete m_effectManager;
    delete m_deviceManager;
    PulseSupport::shutdown();
}

gboolean Backend::busCall(GstBus *bus, GstMessage *msg, gpointer data)
{
    Q_UNUSED(bus);
    Q_ASSERT(msg);

    MediaObject *mediaObject = static_cast<MediaObject*>(data);
    Q_ASSERT(mediaObject);

    Message message(msg, mediaObject);
    QMetaObject::invokeMethod(mediaObject->backend(), "handleBusMessage", Qt::QueuedConnection, Q_ARG(Message, message));

    return true;
}

/***
 * !reimp
 */
QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
{
    // Return nothing if dependencies are not met

    switch (c) {
    case MediaObjectClass:
        return new MediaObject(this, parent);

    case AudioOutputClass:
        return new AudioOutput(this, parent);

    case EffectClass:
        return new AudioEffect(this, args[0].toInt(), parent);

    case AudioDataOutputClass:
        return new AudioDataOutput(this, parent);

    case VideoDataOutputClass:
        logMessage("createObject() : VideoDataOutput not implemented");
        break;

    case VideoWidgetClass: {
            QWidget *widget =  qobject_cast<QWidget*>(parent);
            return new VideoWidget(this, widget);
        }

    case VolumeFaderEffectClass:
        return new VolumeFaderEffect(this, parent);

    case VisualizationClass:  //Fall through
    default:
        logMessage("createObject() : Backend object not available");
    }
    return 0;
}

// Returns true if all dependencies are met
// and gstreamer is usable, otherwise false
bool Backend::isValid() const
{
    return m_isValid;
}

bool Backend::supportsVideo() const
{
    return isValid();
}

bool Backend::checkDependencies() const
{
    bool success = false;
    // Verify that gst-plugins-base is installed
    GstElementFactory *acFactory = gst_element_factory_find ("audioconvert");
    if (acFactory) {
        gst_object_unref(acFactory);
        success = true;
        // Check if gst-plugins-good is installed
        GstElementFactory *csFactory = gst_element_factory_find ("videobalance");
        if (csFactory) {
            gst_object_unref(csFactory);
        } else {
            QString message = tr("Warning: You do not seem to have the package gstreamer0.10-plugins-good installed.\n"
                                 "          Some video features have been disabled.");
            qDebug() << message;
        }
    } else {
        qWarning() << tr("Warning: You do not seem to have the base GStreamer plugins installed.\n"
                         "          All audio and video support has been disabled");
    }
    return success;
}

/***
 * !reimp
 */
QStringList Backend::availableMimeTypes() const
{
    QStringList availableMimeTypes;

    if (!isValid())
        return availableMimeTypes;

    GstElementFactory *mpegFactory;
    // Add mp3 as a separate mime type as people are likely to look for it.
    if ((mpegFactory = gst_element_factory_find ("ffmpeg")) ||
        (mpegFactory = gst_element_factory_find ("mad"))) {
        availableMimeTypes << QLatin1String("audio/x-mp3");
        gst_object_unref(GST_OBJECT(mpegFactory));
    }

    // Iterate over all audio and video decoders and extract mime types from sink caps
    GList* factoryList = gst_registry_get_feature_list(gst_registry_get_default (), GST_TYPE_ELEMENT_FACTORY);
    for (GList* iter = g_list_first(factoryList) ; iter != NULL ; iter = g_list_next(iter)) {
        GstPluginFeature *feature = GST_PLUGIN_FEATURE(iter->data);
        QString klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));

        if (klass == QLatin1String("Codec/Decoder") ||
            klass == QLatin1String("Codec/Decoder/Audio") ||
            klass == QLatin1String("Codec/Decoder/Video") ||
            klass == QLatin1String("Codec/Demuxer") ||
            klass == QLatin1String("Codec/Demuxer/Audio") ||
            klass == QLatin1String("Codec/Demuxer/Video") ||
            klass == QLatin1String("Codec/Parser") ||
            klass == QLatin1String("Codec/Parser/Audio") ||
            klass == QLatin1String("Codec/Parser/Video")) {

            const GList *static_templates;
            GstElementFactory *factory = GST_ELEMENT_FACTORY(feature);
            static_templates = gst_element_factory_get_static_pad_templates(factory);

            for (; static_templates != NULL ; static_templates = static_templates->next) {
                GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *) static_templates->data;
                if (padTemplate && padTemplate->direction == GST_PAD_SINK) {
                    GstCaps *caps = gst_static_pad_template_get_caps (padTemplate);

                    if (caps) {
                        const GstStructure* capsStruct = gst_caps_get_structure (caps, 0);
                        QString mime = QString::fromUtf8(gst_structure_get_name (capsStruct));
                        if (!availableMimeTypes.contains(mime))
                              availableMimeTypes.append(mime);
                    }
                }
            }
        }
    }
    g_list_free(factoryList);
    if (availableMimeTypes.contains("audio/x-vorbis")
        && availableMimeTypes.contains("application/x-ogm-audio")) {
        if (!availableMimeTypes.contains("audio/x-vorbis+ogg"))
            availableMimeTypes.append("audio/x-vorbis+ogg");
        if (!availableMimeTypes.contains("application/ogg"))  /* *.ogg */
            availableMimeTypes.append("application/ogg");
        if (!availableMimeTypes.contains("audio/ogg")) /* *.oga */
            availableMimeTypes.append("audio/ogg");
    }
    availableMimeTypes.sort();
    return availableMimeTypes;
}

/***
 * !reimp
 */
QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
{
    QList<int> list;

    if (!isValid())
        return list;

    PulseSupport *pulse = PulseSupport::getInstance();
    if (pulse->isActive() && (Phonon::AudioOutputDeviceType == type || Phonon::AudioCaptureDeviceType == type))
        return pulse->objectDescriptionIndexes(type);

    switch (type) {
    case Phonon::AudioOutputDeviceType: {
            QList<AudioDevice> deviceList = deviceManager()->audioOutputDevices();
            for (int dev = 0 ; dev < deviceList.size() ; ++dev)
                list.append(deviceList[dev].id);
            break;
        }
        break;

    case Phonon::EffectType: {
            QList<EffectInfo*> effectList = effectManager()->audioEffects();
            for (int eff = 0 ; eff < effectList.size() ; ++eff)
                list.append(eff);
            break;
        }
        break;
    default:
        break;
    }
    return list;
}

/***
 * !reimp
 */
QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
{

    QHash<QByteArray, QVariant> ret;

    if (!isValid())
        return ret;

    PulseSupport *pulse = PulseSupport::getInstance();
    if (pulse->isActive() && (Phonon::AudioOutputDeviceType == type || Phonon::AudioCaptureDeviceType == type))
        return pulse->objectDescriptionProperties(type, index);

    switch (type) {
    case Phonon::AudioOutputDeviceType: {
            AudioDevice* ad;
            if ((ad = deviceManager()->audioDevice(index))) {
                ret.insert("name", ad->gstId);
                ret.insert("description", ad->description);
                ret.insert("icon", ad->icon);
            }
        }
        break;

    case Phonon::EffectType: {
            QList<EffectInfo*> effectList = effectManager()->audioEffects();
            if (index >= 0 && index <= effectList.size()) {
                const EffectInfo *effect = effectList[index];
                ret.insert("name", effect->name());
                ret.insert("description", effect->description());
                ret.insert("author", effect->author());
            } else
                Q_ASSERT(1); // Since we use list position as ID, this should not happen
        }
    default:
        break;
    }
    return ret;
}

/***
 * !reimp
 */
bool Backend::startConnectionChange(QSet<QObject *> objects)
{
    foreach (QObject *object, objects) {
        MediaNode *sourceNode = qobject_cast<MediaNode *>(object);
        MediaObject *media = sourceNode->root();
        if (media) {
            media->saveState();
            return true;
        }
    }
    return true;
}

/***
 * !reimp
 */
bool Backend::connectNodes(QObject *source, QObject *sink)
{
    if (isValid()) {
        MediaNode *sourceNode = qobject_cast<MediaNode *>(source);
        MediaNode *sinkNode = qobject_cast<MediaNode *>(sink);
        if (sourceNode && sinkNode) {
            if (sourceNode->connectNode(sink)) {
                sourceNode->root()->invalidateGraph();
                logMessage(QString("Backend connected %0 to %1").arg(source->metaObject()->className()).arg(sink->metaObject()->className()));
                return true;
            }
        }
    }
    logMessage(QString("Linking %0 to %1 failed").arg(source->metaObject()->className()).arg(sink->metaObject()->className()), Warning);
    return false;
}

/***
 * !reimp
 */
bool Backend::disconnectNodes(QObject *source, QObject *sink)
{
    MediaNode *sourceNode = qobject_cast<MediaNode *>(source);
    MediaNode *sinkNode = qobject_cast<MediaNode *>(sink);

    if (sourceNode && sinkNode)
        return sourceNode->disconnectNode(sink);
    else
        return false;
}

/***
 * !reimp
 */
bool Backend::endConnectionChange(QSet<QObject *> objects)
{
    foreach (QObject *object, objects) {
        MediaNode *sourceNode = qobject_cast<MediaNode *>(object);
        MediaObject *media = sourceNode->root();
        if (media) {
            media->resumeState();
            return true;
        }
    }
    return true;
}

/***
 * Request bus messages for this mediaobject
 */
void Backend::addBusWatcher(MediaObject* node)
{
    Q_ASSERT(node);
    GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(node->pipeline()));
    gst_bus_add_watch (bus, busCall, node);
    gst_object_unref(bus);
}

/***
 * Ignore bus messages for this mediaobject
 */
void Backend::removeBusWatcher(MediaObject* node)
{
    Q_ASSERT(node);
    g_source_remove_by_user_data(node);
}

/***
 * Polls each mediaobject's pipeline and delivers
 * pending any pending messages
 */
void Backend::handleBusMessage(Message message)
{
    MediaObject *mediaObject = message.source();
    mediaObject->handleBusMessage(message);
}

DeviceManager* Backend::deviceManager() const
{
    return m_deviceManager;
}

EffectManager* Backend::effectManager() const
{
    return m_effectManager;
}

/**
 * Returns a debuglevel that is determined by the
 * PHONON_GST_DEBUG environment variable.
 *
 *  Warning - important warnings
 *  Info    - general info
 *  Debug   - gives extra info
 */
Backend::DebugLevel Backend::debugLevel() const
{
    return m_debugLevel;
}

/***
 * Prints a conditional debug message based on the current debug level
 * If obj is provided, classname and objectname will be printed as well
 *
 * see debugLevel()
 */
void Backend::logMessage(const QString &message, int priority, QObject *obj) const
{
    if (debugLevel() > 0) {
        QString output;
        if (obj) {
            // Strip away namespace from className
            QString className(obj->metaObject()->className());
            int nameLength = className.length() - className.lastIndexOf(':') - 1;
            className = className.right(nameLength);
            output.sprintf("%s %s (%s %p)", message.toLatin1().constData(),
                                          obj->objectName().toLatin1().constData(),
                                          className.toLatin1().constData(), obj);
        }
        else {
            output = message;
        }
        if (priority <= (int)debugLevel()) {
            qDebug() << QString("PGST(%1): %2").arg(priority).arg(output);
        }
    }
}

}
}

QT_END_NAMESPACE

#include "moc_backend.cpp"
<commit_msg>gstreamer: Remove unnecessary PulseSupport calls now that the library no longer asks us for this when PA is active.<commit_after>/*  This file is part of the KDE project.

    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

    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 or 3 of the License.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "backend.h"
#include "audiooutput.h"
#include "audiodataoutput.h"
#include "audioeffect.h"
#include "mediaobject.h"
#include "videowidget.h"
#include "devicemanager.h"
#include "effectmanager.h"
#include "message.h"
#include "volumefadereffect.h"
#include <gst/interfaces/propertyprobe.h>
#include <phonon/pulsesupport.h>

#include <QtCore/QSet>
#include <QtCore/QVariant>
#include <QtCore/QtPlugin>

QT_BEGIN_NAMESPACE

Q_EXPORT_PLUGIN2(phonon_gstreamer, Phonon::Gstreamer::Backend)

namespace Phonon
{
namespace Gstreamer
{

class MediaNode;

Backend::Backend(QObject *parent, const QVariantList &)
        : QObject(parent)
        , m_deviceManager(0)
        , m_effectManager(0)
        , m_debugLevel(Warning)
        , m_isValid(false)
{
    // Initialise PulseAudio support
    PulseSupport *pulse = PulseSupport::getInstance();
    connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)), SIGNAL(objectDescriptionChanged(ObjectDescriptionType)));

    // In order to support reloading, we only set the app name once...
    static bool first = true;
    if (first) {
        first = false;
        g_set_application_name(qApp->applicationName().toUtf8());
    }
    GError *err = 0;
    bool wasInit = gst_init_check(0, 0, &err);  //init gstreamer: must be called before any gst-related functions
    if (err)
        g_error_free(err);

    qRegisterMetaType<Message>("Message");

    setProperty("identifier",     QLatin1String("phonon_gstreamer"));
    setProperty("backendName",    QLatin1String("Gstreamer"));
    setProperty("backendComment", QLatin1String("Gstreamer plugin for Phonon"));
    setProperty("backendVersion", QLatin1String("0.2"));
    setProperty("backendWebsite", QLatin1String("http://qtsoftware.com/"));

    //check if we should enable debug output
    QString debugLevelString = qgetenv("PHONON_GST_DEBUG");
    int debugLevel = debugLevelString.toInt();
    if (debugLevel > 3) //3 is maximum
        debugLevel = 3;
    m_debugLevel = (DebugLevel)debugLevel;

    if (wasInit) {
        m_isValid = checkDependencies();
        gchar *versionString = gst_version_string();
        logMessage(QString("Using %0").arg(versionString));
        g_free(versionString);
    }
    if (!m_isValid)
        qWarning("Phonon::GStreamer::Backend: Failed to initialize GStreamer");

    m_deviceManager = new DeviceManager(this);
    m_effectManager = new EffectManager(this);
}

Backend::~Backend()
{
    delete m_effectManager;
    delete m_deviceManager;
    PulseSupport::shutdown();
}

gboolean Backend::busCall(GstBus *bus, GstMessage *msg, gpointer data)
{
    Q_UNUSED(bus);
    Q_ASSERT(msg);

    MediaObject *mediaObject = static_cast<MediaObject*>(data);
    Q_ASSERT(mediaObject);

    Message message(msg, mediaObject);
    QMetaObject::invokeMethod(mediaObject->backend(), "handleBusMessage", Qt::QueuedConnection, Q_ARG(Message, message));

    return true;
}

/***
 * !reimp
 */
QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
{
    // Return nothing if dependencies are not met

    switch (c) {
    case MediaObjectClass:
        return new MediaObject(this, parent);

    case AudioOutputClass:
        return new AudioOutput(this, parent);

    case EffectClass:
        return new AudioEffect(this, args[0].toInt(), parent);

    case AudioDataOutputClass:
        return new AudioDataOutput(this, parent);

    case VideoDataOutputClass:
        logMessage("createObject() : VideoDataOutput not implemented");
        break;

    case VideoWidgetClass: {
            QWidget *widget =  qobject_cast<QWidget*>(parent);
            return new VideoWidget(this, widget);
        }

    case VolumeFaderEffectClass:
        return new VolumeFaderEffect(this, parent);

    case VisualizationClass:  //Fall through
    default:
        logMessage("createObject() : Backend object not available");
    }
    return 0;
}

// Returns true if all dependencies are met
// and gstreamer is usable, otherwise false
bool Backend::isValid() const
{
    return m_isValid;
}

bool Backend::supportsVideo() const
{
    return isValid();
}

bool Backend::checkDependencies() const
{
    bool success = false;
    // Verify that gst-plugins-base is installed
    GstElementFactory *acFactory = gst_element_factory_find ("audioconvert");
    if (acFactory) {
        gst_object_unref(acFactory);
        success = true;
        // Check if gst-plugins-good is installed
        GstElementFactory *csFactory = gst_element_factory_find ("videobalance");
        if (csFactory) {
            gst_object_unref(csFactory);
        } else {
            QString message = tr("Warning: You do not seem to have the package gstreamer0.10-plugins-good installed.\n"
                                 "          Some video features have been disabled.");
            qDebug() << message;
        }
    } else {
        qWarning() << tr("Warning: You do not seem to have the base GStreamer plugins installed.\n"
                         "          All audio and video support has been disabled");
    }
    return success;
}

/***
 * !reimp
 */
QStringList Backend::availableMimeTypes() const
{
    QStringList availableMimeTypes;

    if (!isValid())
        return availableMimeTypes;

    GstElementFactory *mpegFactory;
    // Add mp3 as a separate mime type as people are likely to look for it.
    if ((mpegFactory = gst_element_factory_find ("ffmpeg")) ||
        (mpegFactory = gst_element_factory_find ("mad"))) {
        availableMimeTypes << QLatin1String("audio/x-mp3");
        gst_object_unref(GST_OBJECT(mpegFactory));
    }

    // Iterate over all audio and video decoders and extract mime types from sink caps
    GList* factoryList = gst_registry_get_feature_list(gst_registry_get_default (), GST_TYPE_ELEMENT_FACTORY);
    for (GList* iter = g_list_first(factoryList) ; iter != NULL ; iter = g_list_next(iter)) {
        GstPluginFeature *feature = GST_PLUGIN_FEATURE(iter->data);
        QString klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));

        if (klass == QLatin1String("Codec/Decoder") ||
            klass == QLatin1String("Codec/Decoder/Audio") ||
            klass == QLatin1String("Codec/Decoder/Video") ||
            klass == QLatin1String("Codec/Demuxer") ||
            klass == QLatin1String("Codec/Demuxer/Audio") ||
            klass == QLatin1String("Codec/Demuxer/Video") ||
            klass == QLatin1String("Codec/Parser") ||
            klass == QLatin1String("Codec/Parser/Audio") ||
            klass == QLatin1String("Codec/Parser/Video")) {

            const GList *static_templates;
            GstElementFactory *factory = GST_ELEMENT_FACTORY(feature);
            static_templates = gst_element_factory_get_static_pad_templates(factory);

            for (; static_templates != NULL ; static_templates = static_templates->next) {
                GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *) static_templates->data;
                if (padTemplate && padTemplate->direction == GST_PAD_SINK) {
                    GstCaps *caps = gst_static_pad_template_get_caps (padTemplate);

                    if (caps) {
                        const GstStructure* capsStruct = gst_caps_get_structure (caps, 0);
                        QString mime = QString::fromUtf8(gst_structure_get_name (capsStruct));
                        if (!availableMimeTypes.contains(mime))
                              availableMimeTypes.append(mime);
                    }
                }
            }
        }
    }
    g_list_free(factoryList);
    if (availableMimeTypes.contains("audio/x-vorbis")
        && availableMimeTypes.contains("application/x-ogm-audio")) {
        if (!availableMimeTypes.contains("audio/x-vorbis+ogg"))
            availableMimeTypes.append("audio/x-vorbis+ogg");
        if (!availableMimeTypes.contains("application/ogg"))  /* *.ogg */
            availableMimeTypes.append("application/ogg");
        if (!availableMimeTypes.contains("audio/ogg")) /* *.oga */
            availableMimeTypes.append("audio/ogg");
    }
    availableMimeTypes.sort();
    return availableMimeTypes;
}

/***
 * !reimp
 */
QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
{
    QList<int> list;

    if (!isValid())
        return list;

    switch (type) {
    case Phonon::AudioOutputDeviceType: {
            QList<AudioDevice> deviceList = deviceManager()->audioOutputDevices();
            for (int dev = 0 ; dev < deviceList.size() ; ++dev)
                list.append(deviceList[dev].id);
            break;
        }
        break;

    case Phonon::EffectType: {
            QList<EffectInfo*> effectList = effectManager()->audioEffects();
            for (int eff = 0 ; eff < effectList.size() ; ++eff)
                list.append(eff);
            break;
        }
        break;
    default:
        break;
    }
    return list;
}

/***
 * !reimp
 */
QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
{

    QHash<QByteArray, QVariant> ret;

    if (!isValid())
        return ret;

    switch (type) {
    case Phonon::AudioOutputDeviceType: {
            AudioDevice* ad;
            if ((ad = deviceManager()->audioDevice(index))) {
                ret.insert("name", ad->gstId);
                ret.insert("description", ad->description);
                ret.insert("icon", ad->icon);
            }
        }
        break;

    case Phonon::EffectType: {
            QList<EffectInfo*> effectList = effectManager()->audioEffects();
            if (index >= 0 && index <= effectList.size()) {
                const EffectInfo *effect = effectList[index];
                ret.insert("name", effect->name());
                ret.insert("description", effect->description());
                ret.insert("author", effect->author());
            } else
                Q_ASSERT(1); // Since we use list position as ID, this should not happen
        }
    default:
        break;
    }
    return ret;
}

/***
 * !reimp
 */
bool Backend::startConnectionChange(QSet<QObject *> objects)
{
    foreach (QObject *object, objects) {
        MediaNode *sourceNode = qobject_cast<MediaNode *>(object);
        MediaObject *media = sourceNode->root();
        if (media) {
            media->saveState();
            return true;
        }
    }
    return true;
}

/***
 * !reimp
 */
bool Backend::connectNodes(QObject *source, QObject *sink)
{
    if (isValid()) {
        MediaNode *sourceNode = qobject_cast<MediaNode *>(source);
        MediaNode *sinkNode = qobject_cast<MediaNode *>(sink);
        if (sourceNode && sinkNode) {
            if (sourceNode->connectNode(sink)) {
                sourceNode->root()->invalidateGraph();
                logMessage(QString("Backend connected %0 to %1").arg(source->metaObject()->className()).arg(sink->metaObject()->className()));
                return true;
            }
        }
    }
    logMessage(QString("Linking %0 to %1 failed").arg(source->metaObject()->className()).arg(sink->metaObject()->className()), Warning);
    return false;
}

/***
 * !reimp
 */
bool Backend::disconnectNodes(QObject *source, QObject *sink)
{
    MediaNode *sourceNode = qobject_cast<MediaNode *>(source);
    MediaNode *sinkNode = qobject_cast<MediaNode *>(sink);

    if (sourceNode && sinkNode)
        return sourceNode->disconnectNode(sink);
    else
        return false;
}

/***
 * !reimp
 */
bool Backend::endConnectionChange(QSet<QObject *> objects)
{
    foreach (QObject *object, objects) {
        MediaNode *sourceNode = qobject_cast<MediaNode *>(object);
        MediaObject *media = sourceNode->root();
        if (media) {
            media->resumeState();
            return true;
        }
    }
    return true;
}

/***
 * Request bus messages for this mediaobject
 */
void Backend::addBusWatcher(MediaObject* node)
{
    Q_ASSERT(node);
    GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(node->pipeline()));
    gst_bus_add_watch (bus, busCall, node);
    gst_object_unref(bus);
}

/***
 * Ignore bus messages for this mediaobject
 */
void Backend::removeBusWatcher(MediaObject* node)
{
    Q_ASSERT(node);
    g_source_remove_by_user_data(node);
}

/***
 * Polls each mediaobject's pipeline and delivers
 * pending any pending messages
 */
void Backend::handleBusMessage(Message message)
{
    MediaObject *mediaObject = message.source();
    mediaObject->handleBusMessage(message);
}

DeviceManager* Backend::deviceManager() const
{
    return m_deviceManager;
}

EffectManager* Backend::effectManager() const
{
    return m_effectManager;
}

/**
 * Returns a debuglevel that is determined by the
 * PHONON_GST_DEBUG environment variable.
 *
 *  Warning - important warnings
 *  Info    - general info
 *  Debug   - gives extra info
 */
Backend::DebugLevel Backend::debugLevel() const
{
    return m_debugLevel;
}

/***
 * Prints a conditional debug message based on the current debug level
 * If obj is provided, classname and objectname will be printed as well
 *
 * see debugLevel()
 */
void Backend::logMessage(const QString &message, int priority, QObject *obj) const
{
    if (debugLevel() > 0) {
        QString output;
        if (obj) {
            // Strip away namespace from className
            QString className(obj->metaObject()->className());
            int nameLength = className.length() - className.lastIndexOf(':') - 1;
            className = className.right(nameLength);
            output.sprintf("%s %s (%s %p)", message.toLatin1().constData(),
                                          obj->objectName().toLatin1().constData(),
                                          className.toLatin1().constData(), obj);
        }
        else {
            output = message;
        }
        if (priority <= (int)debugLevel()) {
            qDebug() << QString("PGST(%1): %2").arg(priority).arg(output);
        }
    }
}

}
}

QT_END_NAMESPACE

#include "moc_backend.cpp"
<|endoftext|>