diff options
author | Dimitri John Ledkov <xnox@ubuntu.com> | 2014-06-24 20:05:13 +0100 |
---|---|---|
committer | Dimitri John Ledkov <xnox@ubuntu.com> | 2014-06-24 20:05:13 +0100 |
commit | dd22bd15f6ed3e5eb5c77ab427029be50fe20148 (patch) | |
tree | d9491ee40d80688b7f5b1f20504f022686827a57 /src/base |
libavg (1.8.1-1) unstable; urgency=medium
* New upstream release (Closes: #739664)
* Mark libdc1394-22-dev as linux-any build-dependency.
* Add libvdpau-dev build-dependency.
* Add libavresample-dev build-dependency.
# imported from the archive
Diffstat (limited to 'src/base')
85 files changed, 10453 insertions, 0 deletions
diff --git a/src/base/Backtrace.cpp b/src/base/Backtrace.cpp new file mode 100644 index 0000000..2b85cde --- /dev/null +++ b/src/base/Backtrace.cpp @@ -0,0 +1,120 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "Backtrace.h" + +#include "StringHelper.h" + +#ifndef _WIN32 +#include <execinfo.h> +#include <cxxabi.h> +#endif + +#include <stdlib.h> +#include <iostream> +#include <stdio.h> + +using namespace std; + +namespace avg { + +void dumpBacktrace() +{ +#ifndef _WIN32 + vector<string> sFuncs; + getBacktrace(sFuncs); + vector<string>::iterator it = sFuncs.begin(); + ++it; + for (; it != sFuncs.end(); ++it) { + cerr << " " << *it << endl; + } +#endif +} + +string funcNameFromLine(const string& sLine) +{ + try { +#ifdef __APPLE__ + string::size_type addressPos = sLine.find("0x"); + string::size_type namePos = sLine.find(" ", addressPos); + namePos++; + string::size_type nameEndPos = sLine.find(" ", namePos); +#else + string::size_type namePos = sLine.find("("); + namePos++; + string::size_type nameEndPos = sLine.find_first_of(")+", namePos); +#endif + return sLine.substr(namePos, nameEndPos-namePos); + } catch (exception&) { + return sLine; + } +} + +void consolidateRepeatedLines(vector<string>& sFuncs, unsigned& i, unsigned numSameLines) +{ + unsigned firstSameLine = i - numSameLines; + sFuncs[firstSameLine+1] = " [...]"; + sFuncs.erase(sFuncs.begin()+firstSameLine+2, sFuncs.begin()+i-1); + i = firstSameLine + 3; +} + +void getBacktrace(vector<string>& sFuncs) +{ +#ifndef _WIN32 + void* callstack[128]; + int numFrames = backtrace(callstack, 128); + char** ppszLines = backtrace_symbols(callstack, numFrames); + for (int i = 1; i < numFrames; ++i) { + string sLine = ppszLines[i]; + string sFuncName = funcNameFromLine(sLine); + int result; + char * pszDemangledFuncName = abi::__cxa_demangle(sFuncName.c_str(), 0, 0, + &result); + if (!result) { + sFuncName = pszDemangledFuncName; + free(pszDemangledFuncName); + } + char szLineNum[10]; + sprintf(szLineNum, "%3d", i); + sFuncs.push_back(string(szLineNum)+" "+sFuncName); + } + free(ppszLines); + + unsigned numSameLines = 1; + unsigned i = 1; + for (i = 1; i < sFuncs.size(); ++i) { + if (sFuncs[i].substr(4, string::npos) == sFuncs[i-1].substr(4, string::npos)) { + numSameLines++; + } else { + if (numSameLines > 3) { + consolidateRepeatedLines(sFuncs, i, numSameLines); + } + numSameLines = 1; + } + } + if (numSameLines > 2) { + consolidateRepeatedLines(sFuncs, i, numSameLines); + } +#endif +} + +} + diff --git a/src/base/Backtrace.h b/src/base/Backtrace.h new file mode 100644 index 0000000..2eee387 --- /dev/null +++ b/src/base/Backtrace.h @@ -0,0 +1,36 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Backtrace_H_ +#define _Backtrace_H_ + +#include <vector> +#include <string> + +namespace avg { + +void dumpBacktrace(); + +void getBacktrace(std::vector<std::string>& sFuncs); + +} + +#endif diff --git a/src/base/BezierCurve.cpp b/src/base/BezierCurve.cpp new file mode 100644 index 0000000..7e5fb8e --- /dev/null +++ b/src/base/BezierCurve.cpp @@ -0,0 +1,56 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "BezierCurve.h" + +#include "GLMHelper.h" + +#include <iostream> + +using namespace std; + +namespace avg { + +BezierCurve::BezierCurve(const glm::vec2& p0, const glm::vec2& p1, const glm::vec2& p2, + const glm::vec2& p3) + : m_P0(p0), + m_P1(p1), + m_P2(p2), + m_P3(p3) +{ +} + +glm::vec2 BezierCurve::interpolate(float t) const +{ + return (1.f-t)*(1.f-t)*(1.f-t)*m_P0+ + 3.f*t*(1.f-t)*(1.f-t) *m_P1+ + 3.f*t*t*(1.f-t) *m_P2+ + t*t*t *m_P3; +} + +glm::vec2 BezierCurve::getDeriv(float t) const +{ + return 3.f*(m_P1-m_P0)*(1.f-t)*(1.f-t)+ + 6.f*(m_P2-m_P1)*(1.f-t)*t+ + 3.f*(m_P3-m_P2)*t*t; +} + +} diff --git a/src/base/BezierCurve.h b/src/base/BezierCurve.h new file mode 100644 index 0000000..b2ec1dc --- /dev/null +++ b/src/base/BezierCurve.h @@ -0,0 +1,56 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _BezierCurve_H_ +#define _BezierCurve_H_ + +#include "../api.h" + +#include "../glm/glm.hpp" + +#include <boost/shared_ptr.hpp> +#include <vector> + +namespace avg { + +class AVG_API BezierCurve { +public: + BezierCurve(const glm::vec2& p0, const glm::vec2& p1, const glm::vec2& p2, + const glm::vec2& p3); + + glm::vec2 interpolate(float t) const; + glm::vec2 getDeriv(float t) const; + +private: + glm::vec2 m_P0; + glm::vec2 m_P1; + glm::vec2 m_P2; + glm::vec2 m_P3; +}; + +typedef boost::shared_ptr<BezierCurve> BezierCurvePtr; + +} + +#endif + + + diff --git a/src/base/CmdQueue.h b/src/base/CmdQueue.h new file mode 100644 index 0000000..9d38f37 --- /dev/null +++ b/src/base/CmdQueue.h @@ -0,0 +1,56 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _CmdQueue_H_ +#define _CmdQueue_H_ + +#include "Command.h" +#include "Queue.h" + +#include "../api.h" + +namespace avg { + +template<class RECEIVER> +class AVG_TEMPLATE_API CmdQueue: public Queue<Command<RECEIVER> > +{ +public: + CmdQueue(int maxSize=-1); + typedef typename Queue<Command<RECEIVER> >::QElementPtr CmdPtr; + void pushCmd(typename Command<RECEIVER>::CmdFunc func); + +}; + +template<class RECEIVER> +CmdQueue<RECEIVER>::CmdQueue(int maxSize) + : Queue<Command<RECEIVER> >(maxSize) +{ +} + +template<class RECEIVER> +void CmdQueue<RECEIVER>::pushCmd(typename Command<RECEIVER>::CmdFunc func) +{ + this->push(CmdPtr(new Command<RECEIVER>(func))); +} + +} + +#endif diff --git a/src/base/Command.h b/src/base/Command.h new file mode 100644 index 0000000..fe18171 --- /dev/null +++ b/src/base/Command.h @@ -0,0 +1,56 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Command_H_ +#define _Command_H_ + +#include "../api.h" +#include <boost/function.hpp> + +namespace avg { + +template<class RECEIVER> +class AVG_TEMPLATE_API Command { +public: + typedef boost::function<void(RECEIVER*)> CmdFunc; + + Command(CmdFunc Func); + void execute(RECEIVER* pTarget); + +private: + CmdFunc m_Func; +}; + +template<class RECEIVER> +Command<RECEIVER>::Command(CmdFunc Func) + : m_Func(Func) +{ +} + +template<class RECEIVER> +void Command<RECEIVER>::execute(RECEIVER* pTarget) +{ + m_Func(pTarget); +} + +} + +#endif diff --git a/src/base/ConfigMgr.cpp b/src/base/ConfigMgr.cpp new file mode 100644 index 0000000..0414037 --- /dev/null +++ b/src/base/ConfigMgr.cpp @@ -0,0 +1,361 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "ConfigMgr.h" +#include "Logger.h" +#include "Exception.h" +#include "OSHelper.h" + +#include <libxml/xmlmemory.h> + +#include <iostream> +#include <stdlib.h> +#include <errno.h> + +#ifndef _WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif + +using namespace std; + +namespace avg { + +ConfigOption::ConfigOption(const string& sName, const string& sValue) + : m_sName(sName), + m_sValue(sValue) +{ +} + +ConfigMgr* ConfigMgr::m_pGlobalConfigMgr = 0; + +void deleteConfigMgr() +{ + delete ConfigMgr::m_pGlobalConfigMgr; + ConfigMgr::m_pGlobalConfigMgr = 0; +} + +ConfigMgr* ConfigMgr::get() +{ + if (!m_pGlobalConfigMgr) { + m_pGlobalConfigMgr = new ConfigMgr; + atexit(deleteConfigMgr); + } + return m_pGlobalConfigMgr; +} + +ConfigMgr::ConfigMgr() +{ + addSubsys("scr"); + addOption("scr", "gles", "false"); + addOption("scr", "bpp", "24"); + addOption("scr", "fullscreen", "false"); + addOption("scr", "windowwidth", "0"); + addOption("scr", "windowheight", "0"); + addOption("scr", "dotspermm", "0"); + addOption("scr", "usepow2textures", "false"); + addOption("scr", "usepixelbuffers", "true"); + addOption("scr", "multisamplesamples", "8"); + addOption("scr", "shaderusage", "auto"); + addOption("scr", "gamma", "-1,-1,-1"); + addOption("scr", "vsyncmode", "auto"); + addOption("scr", "videoaccel", "true"); + + addSubsys("aud"); + addOption("aud", "channels", "2"); + addOption("aud", "samplerate", "44100"); + addOption("aud", "outputbuffersamples", "1024"); + + addSubsys("gesture"); + addOption("gesture", "maxtapdist", "15"); + addOption("gesture", "maxdoubletaptime", "300"); + addOption("gesture", "minswipedist", "50"); + addOption("gesture", "swipedirectiontolerance", "0.393"); // pi/8 + addOption("gesture", "maxswipecontactdist", "100"); + addOption("gesture", "holddelay", "500"); + addOption("gesture", "mindragdist", "5"); + addOption("gesture", "filtermincutoff", "0.1"); + addOption("gesture", "filterbeta", "0.03"); + addOption("gesture", "friction", "-1"); + + addSubsys("touch"); + addOption("touch", "area", "0, 0"); + addOption("touch", "offset", "0, 0"); + + m_sFName = "avgrc"; + loadFile(getGlobalConfigDir()+m_sFName); + char * pHome = getenv("HOME"); + if (pHome) { + loadFile(string(pHome)+"/."+m_sFName); + } +} + +void ConfigMgr::addSubsys(const string& sName) +{ + m_SubsysOptionMap[sName] = ConfigOptionVector(); +} + +void ConfigMgr::addOption(const string& sSubsys, const string& sName, + const std::string& sDefault) +{ + ConfigOptionVector& Subsys = m_SubsysOptionMap[sSubsys]; + Subsys.push_back(ConfigOption(sName, sDefault)); +} + +const ConfigOptionVector* ConfigMgr::getOptions(const string& sSubsys) const +{ + SubsysOptionMap::const_iterator it = m_SubsysOptionMap.find(sSubsys); + if (it == m_SubsysOptionMap.end()) { + return 0; + } else { + return &(*it).second; + } +} + +const string* ConfigMgr::getOption(const string& sSubsys, + const string& sName) const +{ + const ConfigOptionVector* pOptionVector = getOptions(sSubsys); + if (!pOptionVector) { + return 0; + } else { + for (unsigned int i=0; i<pOptionVector->size(); i++) { + if ((*pOptionVector)[i].m_sName == sName) { + return &(*pOptionVector)[i].m_sValue; + } + } + return 0; + } +} + +bool ConfigMgr::getBoolOption(const string& sSubsys, + const string& sName, bool bDefault) const +{ + const string * psOption = getOption(sSubsys, sName); + if (psOption == 0) { + return bDefault; + } + if (*psOption == "true") { + return true; + } else if (*psOption == "false") { + return false; + } else { + AVG_LOG_ERROR(m_sFName << ": Unrecognized value for option " << sName << ": " + << *psOption << ". Must be true or false. Aborting."); + exit(-1); + } +} + +int ConfigMgr::getIntOption(const string& sSubsys, + const string& sName, int Default) const +{ + errno = 0; + const string * psOption = getOption(sSubsys, sName); + if (psOption == 0) { + return Default; + } + int Result = strtol(psOption->c_str(), 0, 10); + int rc = errno; + if (rc == EINVAL || rc == ERANGE) { + AVG_LOG_ERROR(m_sFName << ": Unrecognized value for option "<<sName<<": " + << *psOption << ". Must be an integer. Aborting."); + exit(-1); + } + return Result; +} + +void ConfigMgr::getGammaOption(const string& sSubsys, + const string& sName, float* Val) const +{ + const string * psOption = getOption(sSubsys, sName); + if (psOption == 0) { + return; + } + int rc = sscanf(psOption->c_str(), "%f,%f,%f", Val, Val+1, Val+2); + if (rc < 3) { + AVG_LOG_ERROR(m_sFName << ": Unrecognized value for option "<<sName<<": " + << *psOption << ". Must be three comma-separated numbers. Aborting."); + exit(-1); + } +} + +glm::vec2 ConfigMgr::getSizeOption(const string& sSubsys, + const string& sName) const +{ + const string * psOption = getOption(sSubsys, sName); + if (psOption == 0) { + return glm::vec2(0, 0); + } + float val[2]; + int rc = sscanf(psOption->c_str(), "%f,%f", val, val+1); + if (rc < 2) { + AVG_LOG_ERROR(m_sFName << ": Unrecognized value for option " << sName << ": " + << *psOption << ". Must be 2 comma-separated numbers(x, y). Aborting."); + exit(-1); + } + return glm::vec2(val[0], val[1]); +} + +void ConfigMgr::getStringOption(const string& sSubsys, + const string& sName, const string& sDefault, string& sVal) const +{ + const string * psOption = getOption(sSubsys, sName); + if (psOption == 0) { + sVal = sDefault; + } else { + sVal = *psOption; + } +} + + +bool ConfigMgr::loadFile(const std::string& sPath) +{ + string sSubsys; + try { +#ifndef _WIN32 + // I don't think read permissions on config files are an issue under windows. + int err = access(sPath.c_str(), R_OK); + if (err == -1) { + if (errno == EACCES) { + AVG_LOG_WARNING(sPath+ + ": File exists, but process doesn't have read permissions!"); + } + return false; + } +#else + // but this actually prevents ugly XML parsing errors when file does not exist + // and cygwin is used + int err = _access(sPath.c_str(), 0); + if (err == -1) { + return false; + } +#endif + xmlDocPtr doc; + doc = xmlParseFile(sPath.c_str()); + if (!doc) { + throw Exception(AVG_ERR_XML_VALID, "Error parsing "+sPath + +". File is not well-formed."); + } + xmlNodePtr pRoot = xmlDocGetRootElement(doc); + if (xmlStrcmp(pRoot->name, (const xmlChar *)(m_sFName.c_str()))) { + AVG_LOG_ERROR(sPath+": Root node must be <"+m_sFName+">, found " + << pRoot->name << ". Aborting."); + exit(255); + } + xmlNodePtr pSubsysNode = pRoot->xmlChildrenNode; + while (pSubsysNode) { + if (xmlStrcmp(pSubsysNode->name, (const xmlChar *)"text") && + xmlStrcmp(pSubsysNode->name, (const xmlChar *)"comment")) + { + sSubsys = ((const char *)pSubsysNode->name); + xmlNodePtr pOptionNode = pSubsysNode->xmlChildrenNode; + if (!pOptionNode) { + AVG_LOG_ERROR(sPath << ": Option " << sSubsys + << " has no value. Ignoring."); + } else { + ConfigOptionVector& CurSubsys = getSubsys(sSubsys); + while (pOptionNode) { + if (xmlStrcmp(pOptionNode->name, (const xmlChar *)"text") && + xmlStrcmp(pOptionNode->name, (const xmlChar *)"comment")) + { + setOption(CurSubsys, doc, pOptionNode); + } + pOptionNode = pOptionNode->next; + } + } + } + pSubsysNode = pSubsysNode->next; + } + xmlFreeDoc(doc); + } catch (Exception& e) { + switch (e.getCode()) { + case AVG_ERR_OPTION_SUBSYS_UNKNOWN: + AVG_LOG_ERROR("While parsing " << sPath << ": Option group " << + e.getStr() << " unknown. Aborting."); + exit(255); + case AVG_ERR_OPTION_UNKNOWN: + AVG_LOG_ERROR("While parsing " << sPath << ": Option " << sSubsys << + ":" << e.getStr() << " unknown. Aborting."); + exit(255); + default: + throw; + } + } + return true; +} + +ConfigOptionVector& ConfigMgr::getSubsys(const string& sName) +{ + SubsysOptionMap::iterator pos = m_SubsysOptionMap.find(sName); + if (pos == m_SubsysOptionMap.end()) { + throw Exception(AVG_ERR_OPTION_SUBSYS_UNKNOWN, sName); + } else { + return pos->second; + } +} + +void ConfigMgr::setOption(ConfigOptionVector& optionVector, + xmlDocPtr doc, xmlNodePtr pNode) +{ + string sName = (const char *)pNode->name; + xmlChar * pVal = xmlNodeListGetString(doc, pNode->xmlChildrenNode, 1); + string sValue = (const char *)pVal; + xmlFree(pVal); + setOption(optionVector, sName, sValue); +} + +void ConfigMgr::setOption(ConfigOptionVector& optionVector, + const string& sName, const string& sValue) +{ + for (unsigned int i = 0; i < optionVector.size(); i++) { + if (optionVector[i].m_sName == sName) { + optionVector[i].m_sValue = sValue; + return; + } + } + throw Exception(AVG_ERR_OPTION_UNKNOWN, sName); +} + +void ConfigMgr::dump() const +{ + SubsysOptionMap::const_iterator it; + for (it = m_SubsysOptionMap.begin(); it != m_SubsysOptionMap.end(); ++it) { + cerr << (*it).first << ": " << endl; + const ConfigOptionVector& SubsysOptions = (*it).second; + for (unsigned int j = 0; j < SubsysOptions.size(); ++j) { + cerr << " " << SubsysOptions[j].m_sName << ": " + << SubsysOptions[j].m_sValue << endl; + } + } +} + +string getGlobalConfigDir() +{ +#ifdef _WIN32 + return getAvgLibPath()+"/etc/"; +#else + return "/etc/"; +#endif +} + +} + diff --git a/src/base/ConfigMgr.h b/src/base/ConfigMgr.h new file mode 100644 index 0000000..e2af8f1 --- /dev/null +++ b/src/base/ConfigMgr.h @@ -0,0 +1,93 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _ConfigMgr_H_ +#define _ConfigMgr_H_ + +#include "../api.h" + +#include "GLMHelper.h" +#include <libxml/parser.h> + +#include <string> +#include <vector> +#include <map> + +namespace avg { + +struct ConfigOption { + ConfigOption(const std::string& sName, const std::string& sValue); + + std::string m_sName; + std::string m_sValue; +}; + +typedef std::vector<ConfigOption> ConfigOptionVector; + +class AVG_API ConfigMgr { +public: + static ConfigMgr* get(); + + void addSubsys(const std::string& sName); + void addOption(const std::string& sSubsys, const std::string& sName, + const std::string& sDefault); + + const ConfigOptionVector* getOptions(const std::string& sSubsys) const; + const std::string* getOption(const std::string& sSubsys, + const std::string& sName) const; + bool getBoolOption(const std::string& sSubsys, + const std::string& sName, bool bDefault) const; + int getIntOption(const std::string& sSubsys, + const std::string& sName, int Default) const; + void getGammaOption(const std::string& sSubsys, + const std::string& sName, float* Val) const; + glm::vec2 getSizeOption(const std::string& sSubsys, + const std::string& sName) const; + void getStringOption(const std::string& sSubsys, + const std::string& sName, const std::string& sDefault, std::string& sVal) + const; + + void dump() const; + +private: + ConfigMgr(); + + bool loadFile(const std::string& sPath); + ConfigOptionVector& getSubsys(const std::string& sName); + void setOption(ConfigOptionVector& optionVector, + xmlDocPtr doc, xmlNodePtr pNode); + void setOption(ConfigOptionVector& optionVector, const std::string& sName, + const std::string& sValue); + + typedef std::map<std::string, ConfigOptionVector> SubsysOptionMap; + SubsysOptionMap m_SubsysOptionMap; + + std::string m_sFName; + + static ConfigMgr* m_pGlobalConfigMgr; + friend void deleteConfigMgr(); +}; + +std::string getGlobalConfigDir(); + +} +#endif + diff --git a/src/base/CubicSpline.cpp b/src/base/CubicSpline.cpp new file mode 100644 index 0000000..105563d --- /dev/null +++ b/src/base/CubicSpline.cpp @@ -0,0 +1,104 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "CubicSpline.h" +#include "Exception.h" +#include "MathHelper.h" + +#include <iostream> + +using namespace std; + +namespace avg { + +CubicSpline::CubicSpline(const vector<float>& x, const vector<float>& y, bool bLoop) +{ + AVG_ASSERT(x.size() == y.size()); + for (unsigned i=0; i<x.size(); ++i) { + m_Pts.push_back(glm::vec2(x[i], y[i])); + } + init(); +} + +CubicSpline::CubicSpline(const vector<glm::vec2>& pts, bool bLoop) + : m_Pts(pts) +{ + init(); +} + +CubicSpline::~CubicSpline() +{ +} + +float CubicSpline::interpolate(float orig) +{ + int len = m_Pts.size(); + int low = 0; + int high = len-1; + // Binary search. + while (high - low > 1) { + int avg = (high+low) / 2; + if (m_Pts[avg].x > orig) { + high = avg; + } else { + low = avg; + } + } + float h = m_Pts[high].x - m_Pts[low].x; + float a = (m_Pts[high].x-orig)/h; + float b = (orig-m_Pts[low].x)/h; + + float y = a*m_Pts[low].y + b*m_Pts[high].y + + ((a*a*a-a)*m_Y2[low] + (b*b*b-b)*m_Y2[high])*(h*h)/6.f; + return y; +} + +void CubicSpline::init() +{ + int len = m_Pts.size(); + for (int i=1; i<len; ++i) { + if (m_Pts[i].x <= m_Pts[i-1].x) { + throw Exception(AVG_ERR_INVALID_ARGS, + "CubicSplines must have increasing x coordinates."); + } + } + vector<float> u(len-1,0); + m_Y2.push_back(0.f); + u[0] = 0.f; + for (int i=1; i<len-1; ++i) { + float sig = (m_Pts[i].x-m_Pts[i-1].x) / (m_Pts[i+1].x-m_Pts[i-1].x); + float p = sig * m_Y2[i-1]+2.0f; + m_Y2.push_back((sig-1.0f)/p); + u[i] = (m_Pts[i+1].y-m_Pts[i].y) / (m_Pts[i+1].x-m_Pts[i].x) - + (m_Pts[i].y - m_Pts[i-1].y) / (m_Pts[i].x-m_Pts[i-1].x); + u[i] = (6.f*u[i]/(m_Pts[i+1].x-m_Pts[i-1].x) - sig*u[i-1]) / p; + } + float qn = 0.f; + float un = 0.f; + + m_Y2.push_back((un-qn*u[len-2]) / (qn*m_Y2[len-2]-1.0f)); + + for (int i=len-2; i>=0; i--) { + m_Y2[i] = m_Y2[i]*m_Y2[i+1]+u[i]; + } +} + +} diff --git a/src/base/CubicSpline.h b/src/base/CubicSpline.h new file mode 100644 index 0000000..a275413 --- /dev/null +++ b/src/base/CubicSpline.h @@ -0,0 +1,56 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _CubicSpline_H_ +#define _CubicSpline_H_ + +#include "../api.h" +#include "../glm/glm.hpp" + +#include <boost/shared_ptr.hpp> +#include <vector> + +namespace avg { + +class AVG_API CubicSpline { +public: + CubicSpline(const std::vector<float>& x, const std::vector<float>& y, + bool bLoop=false); + CubicSpline(const std::vector<glm::vec2>& pts, bool bLoop=false); + virtual ~CubicSpline(); + + float interpolate(float orig); + +private: + void init(); + + std::vector<glm::vec2> m_Pts; + std::vector<float> m_Y2; // Second derivatives +}; + +typedef boost::shared_ptr<CubicSpline> CubicSplinePtr; + +} + +#endif + + + diff --git a/src/base/DAG.cpp b/src/base/DAG.cpp new file mode 100644 index 0000000..85ab8bb --- /dev/null +++ b/src/base/DAG.cpp @@ -0,0 +1,130 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "DAG.h" + +#include "Exception.h" + +#include <boost/enable_shared_from_this.hpp> + +using namespace std; + +namespace avg { + +class AVG_API DAGNode: public boost::enable_shared_from_this<DAGNode> +{ +public: + DAGNode(long vertexID, const std::set<long>& outgoingIDs); + void resolveIDs(DAG* pDAG); + + long m_VertexID; + std::set<long> m_OutgoingIDs; + std::set<DAGNodePtr> m_pOutgoingNodes; + std::set<DAGNodePtr> m_pIncomingNodes; +}; + + +DAGNode::DAGNode(long vertexID, const set<long>& outgoingIDs) +{ + m_VertexID = vertexID; + m_OutgoingIDs = outgoingIDs; +} + +void DAGNode::resolveIDs(DAG* pDAG) +{ + set<long>::iterator it; + for (it=m_OutgoingIDs.begin(); it!=m_OutgoingIDs.end(); ++it) { + long outgoingID = *it; + DAGNodePtr pDestNode = pDAG->findNode(outgoingID); + m_pOutgoingNodes.insert(pDestNode); + pDestNode->m_pIncomingNodes.insert(shared_from_this()); + } + m_OutgoingIDs.clear(); +} + + +DAG::DAG() +{ +} + +DAG::~DAG() +{ +} + +void DAG::addNode(long vertexID, const set<long>& outgoingIDs) +{ + DAGNode* pNode = new DAGNode(vertexID, outgoingIDs); + m_pNodes.insert(DAGNodePtr(pNode)); +} + +void DAG::sort(vector<long>& pResults) +{ + resolveIDs(); + while (!m_pNodes.empty()) { + DAGNodePtr pCurNode = findStartNode(*m_pNodes.begin()); + removeNode(pCurNode); + pResults.push_back(pCurNode->m_VertexID); + } +} + +void DAG::resolveIDs() +{ + set<DAGNodePtr>::iterator it; + for (it=m_pNodes.begin(); it!=m_pNodes.end(); ++it) { + (*it)->resolveIDs(this); + } +} + +DAGNodePtr DAG::findNode(long id) +{ + set<DAGNodePtr>::iterator it; + for (it=m_pNodes.begin(); it!=m_pNodes.end(); ++it) { + if ((*it)->m_VertexID == id) { + return (*it); + } + } + AVG_ASSERT(false); + return DAGNodePtr(); +} + +void DAG::removeNode(DAGNodePtr pNode) +{ + set<DAGNodePtr>::iterator it; + for (it=pNode->m_pOutgoingNodes.begin(); it!=pNode->m_pOutgoingNodes.end(); ++it) { + DAGNodePtr pDestNode = *it; + pDestNode->m_pIncomingNodes.erase(pNode); + } + m_pNodes.erase(pNode); +} + +DAGNodePtr DAG::findStartNode(DAGNodePtr pNode, unsigned depth) +{ + if (pNode->m_pIncomingNodes.empty()) { + return pNode; + } else { + if (depth > m_pNodes.size()) { + throw Exception(AVG_ERR_INVALID_ARGS, "cyclic graph"); + } + return findStartNode(*pNode->m_pIncomingNodes.begin(), depth+1); + } +} + +} diff --git a/src/base/DAG.h b/src/base/DAG.h new file mode 100644 index 0000000..929ecd2 --- /dev/null +++ b/src/base/DAG.h @@ -0,0 +1,64 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _DAG_H_ +#define _DAG_H_ + +#include "../api.h" + +#include <set> +#include <vector> +#include <boost/shared_ptr.hpp> + +namespace avg { + +class DAG; +class DAGNode; +typedef boost::shared_ptr<DAGNode> DAGNodePtr; + +// Directed Acyclic Graph class. +// Only useful for sorting. The process of sorting destroys the DAG. +class AVG_API DAG +{ +public: + DAG(); + virtual ~DAG(); + + void addNode(long vertexID, const std::set<long>& outgoingIDs); + void sort(std::vector<long>& pResults); + +private: + friend class DAGNode; + + void resolveIDs(); + DAGNodePtr findNode(long pID); + void removeNode(DAGNodePtr pNode); + DAGNodePtr findStartNode(DAGNodePtr pNode, unsigned depth=0); + + std::set<DAGNodePtr> m_pNodes; +}; + +} + +#endif + + + diff --git a/src/base/DirEntry.cpp b/src/base/DirEntry.cpp new file mode 100644 index 0000000..c654e50 --- /dev/null +++ b/src/base/DirEntry.cpp @@ -0,0 +1,65 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "DirEntry.h" + +using namespace std; + +namespace avg { + +#ifdef _WIN32 +DirEntry::DirEntry(string sDirName, const _finddata_t& findData) + : m_sDirName(sDirName), + m_FindData(findData) +{ +} + +#else +DirEntry::DirEntry(string sDirName, dirent * pEntry) + : m_sDirName(sDirName), + m_pEntry(pEntry) +{ +} +#endif + +DirEntry::~DirEntry() +{ +} + +std::string DirEntry::getName() +{ +#ifdef _WIN32 + return m_FindData.name; +#else + return m_pEntry->d_name; +#endif +} + +void DirEntry::remove() +{ +#ifdef _WIN32 + ::_unlink((m_sDirName+"\\"+m_FindData.name).c_str()); +#else + ::unlink((m_sDirName+"/"+m_pEntry->d_name).c_str()); +#endif +} + +} diff --git a/src/base/DirEntry.h b/src/base/DirEntry.h new file mode 100644 index 0000000..ac2fca9 --- /dev/null +++ b/src/base/DirEntry.h @@ -0,0 +1,67 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _DirEntry_H_ +#define _DirEntry_H_ + +#include "../api.h" +#include <boost/shared_ptr.hpp> + +#ifdef _WIN32 +#include <io.h> +#else +#include <dirent.h> +#endif +#include <string> + +namespace avg { + +class AVG_API DirEntry { +public: +#ifdef _WIN32 + DirEntry(std::string sDirName, const _finddata_t& findData); +#else + DirEntry(std::string sDirName, dirent * pEntry); +#endif + virtual ~DirEntry(); + + std::string getName(); + void remove(); + +private: + std::string m_sDirName; + +#ifdef _WIN32 + _finddata_t m_FindData; +#else + dirent * m_pEntry; +#endif + +}; + +typedef boost::shared_ptr<DirEntry> DirEntryPtr; + +} + +#endif + + + diff --git a/src/base/Directory.cpp b/src/base/Directory.cpp new file mode 100644 index 0000000..bc40ecc --- /dev/null +++ b/src/base/Directory.cpp @@ -0,0 +1,135 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "Directory.h" + +#ifdef _WIN32 +#include <Windows.h> +#endif +#include <sys/stat.h> +#include <iostream> + +using namespace std; + +namespace avg { + +Directory::Directory(std::string sName) + : m_sName(sName) +{ +#ifdef _WIN32 + m_hFile = -1; +#else + m_pDir = 0; +#endif +} + +Directory::~Directory() +{ +#ifdef _WIN32 + _findclose(m_hFile); +#else + if (m_pDir) { + closedir(m_pDir); + } +#endif +} + +int Directory::open(bool bCreateIfMissing) +{ +#ifdef _WIN32 + m_hFile = _findfirst((m_sName+"/*").c_str(), &m_FindData); + if(m_hFile == -1L) { + if (bCreateIfMissing) { + int err = CreateDirectory(m_sName.c_str(), 0); + if (err == 0) { + return -1; + } else { + m_hFile = _findfirst((m_sName+"/*").c_str(), &m_FindData); + m_bFirstFile = true; + return 0; + } + } else { + return -1; + } + } else { + m_bFirstFile = true; + return 0; + } +#else + m_pDir = opendir(m_sName.c_str()); + if (!m_pDir) { + if (bCreateIfMissing) { + int err = mkdir(m_sName.c_str(), + S_IRWXU | S_IRWXG | S_IRWXO); + if (err) { + return err; + } else { + m_pDir = opendir(m_sName.c_str()); + return 0; + } + } else { + return -1; + } + } else { + return 0; + } +#endif +} + +DirEntryPtr Directory::getNextEntry() +{ +#ifdef _WIN32 + if (!m_bFirstFile) { + int rc = _findnext(m_hFile, &m_FindData); + if (rc == -1) { + return DirEntryPtr(); + } + } + m_bFirstFile = false; + return DirEntryPtr(new DirEntry(m_sName, m_FindData)); +#else + dirent * pDirent; + pDirent = readdir(m_pDir); + if (pDirent) { + return DirEntryPtr(new DirEntry(m_sName, pDirent)); + } else { + return DirEntryPtr(); + } +#endif +} + +const std::string& Directory::getName() +{ + return m_sName; +} + +void Directory::empty() +{ + DirEntryPtr pEntry; + do { + pEntry = getNextEntry(); + if (pEntry) { + pEntry->remove(); + } + } while (pEntry); +} + +} diff --git a/src/base/Directory.h b/src/base/Directory.h new file mode 100644 index 0000000..f75107d --- /dev/null +++ b/src/base/Directory.h @@ -0,0 +1,64 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Directory_H_ +#define _Directory_H_ + +#include "../api.h" +#include "DirEntry.h" + +#ifdef _WIN32 +#include <io.h> +#else +#include <dirent.h> +#endif + +#include <string> + +namespace avg { + +class AVG_API Directory { +public: + Directory(std::string sName); + virtual ~Directory(); + + int open(bool bCreateIfMissing = false); + DirEntryPtr getNextEntry(); + const std::string& getName(); + void empty(); + +private: + std::string m_sName; + +#ifdef _WIN32 + _finddata_t m_FindData; + intptr_t m_hFile; + bool m_bFirstFile; +#else + DIR * m_pDir; +#endif +}; + +} + +#endif + + diff --git a/src/base/DlfcnWrapper.cpp b/src/base/DlfcnWrapper.cpp new file mode 100644 index 0000000..f8011b1 --- /dev/null +++ b/src/base/DlfcnWrapper.cpp @@ -0,0 +1,61 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "DlfcnWrapper.h" + +#include <sstream> +#include <string.h> + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include "windows.h" + +using namespace std; + +namespace avg { + +void* dlopen(const char *pszPath, int ignored) +{ + return LoadLibrary(pszPath); +} + +void dlclose(void* handle) +{ + FreeLibrary((HMODULE)handle); +} + +void* dlsym(void* handle, const char* functionName) +{ + return GetProcAddress((HMODULE)handle, functionName); +} + +const char* dlerror() +{ + static char buffer[1024]; + int err = GetLastError(); + ostringstream ss; + ss << err; + strncpy(buffer,ss.str().c_str(),1023); + return buffer; +} + +} diff --git a/src/base/DlfcnWrapper.h b/src/base/DlfcnWrapper.h new file mode 100644 index 0000000..883fb37 --- /dev/null +++ b/src/base/DlfcnWrapper.h @@ -0,0 +1,41 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _DlfcnWrapper_h_ +#define _DlfcnWrapper_h_ + +#ifdef _WIN32 +#define RTLD_LOCAL 0 +#define RTLD_NOW 0 + +namespace avg { + +void* dlopen(const char *pszPath, int ignored); +void dlclose(void* handle); +void* dlsym(void* handle, const char* functionName); +const char* dlerror(); + +} +#else +#include <dlfcn.h> +#endif + +#endif diff --git a/src/base/Exception.cpp b/src/base/Exception.cpp new file mode 100644 index 0000000..eb4f03c --- /dev/null +++ b/src/base/Exception.cpp @@ -0,0 +1,99 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "Exception.h" +#include "Backtrace.h" +#include "Logger.h" +#include "OSHelper.h" + +#include <cstdlib> +#include <sstream> + +#ifdef WIN32 +#include <intrin.h> +#endif + +using namespace std; + +namespace avg { + +Exception::Exception(int code, const string& sErr) + : std::exception(), + m_Code (code), + m_sErr (sErr) +{ +} + +Exception::Exception(const Exception& ex) + : std::exception(), + m_Code (ex.getCode()), + m_sErr (ex.getStr()) +{ +} + +Exception::~Exception() throw() +{ +} + +int Exception::getCode() const +{ + return m_Code; +} + +const string& Exception::getStr() const +{ + return m_sErr; +} + +const char* Exception::what() const throw() +{ + return m_sErr.c_str(); +} + +void debugBreak() +{ +#ifdef _WIN32 + __debugbreak(); +#else + __builtin_trap(); +#endif +} + +void avgAssert(bool b, const char * pszFile, int line, const char * pszReason) +{ + if (!b) { + string sDummy; + static bool bBreak = getEnv("AVG_BREAK_ON_ASSERT", sDummy); + if (bBreak) { + debugBreak(); + } else { + stringstream ss; + ss << "Assertion failed in " << pszFile << ": " << line << endl; + if (pszReason) { + ss << "Reason: " << pszReason << endl; + } + dumpBacktrace(); + throw(Exception(AVG_ERR_ASSERT_FAILED, ss.str())); + } + } +} + +} diff --git a/src/base/Exception.h b/src/base/Exception.h new file mode 100644 index 0000000..b28dc1a --- /dev/null +++ b/src/base/Exception.h @@ -0,0 +1,88 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Exception_H_ +#define _Exception_H_ + +#include "../api.h" +#include <string> +#include <exception> + +#define AVG_ERR_UNKNOWN -1 +#define AVG_ERR_XML_PARSE 1 +#define AVG_ERR_XML_VALID 2 +#define AVG_ERR_XML_EMPTY 3 +#define AVG_ERR_XML_NODE_UNKNOWN 4 +#define AVG_ERR_XML_DUPLICATE_ID 5 +#define AVG_ERR_VIDEO_INIT_FAILED 6 +#define AVG_ERR_VIDEO_GENERAL 7 +#define AVG_ERR_FONT_INIT_FAILED 10 +#define AVG_ERR_VIDEO_LOAD_FAILED 11 +#define AVG_ERR_UNSUPPORTED 12 +#define AVG_ERR_OPTION_SUBSYS_UNKNOWN 13 +#define AVG_ERR_OPTION_UNKNOWN 14 +#define AVG_ERR_FILEIO 15 +#define AVG_ERR_NOT_IN_SCENE 16 +#define AVG_ERR_OUT_OF_RANGE 17 +#define AVG_ERR_ALREADY_CONNECTED 18 +#define AVG_ERR_LOAD_DURING_PLAYBACK 19 +#define AVG_ERR_CANT_PARSE_STRING 20 +#define AVG_ERR_INVALID_CAPTURE 21 + +#define AVG_ERR_NO_NODE 23 +#define AVG_ERR_NO_ARG 24 +#define AVG_ERR_INVALID_ARGS 25 +#define AVG_ERR_NO_BUILDER 26 +#define AVG_ERR_TYPE 27 +#define AVG_ERR_CORRUPT_PLUGIN 28 +#define AVG_ERR_CAMERA_FATAL 29 +#define AVG_ERR_CAMERA_NONFATAL 30 +#define AVG_ERR_DEPRECATED 31 +#define AVG_ERR_ASSERT_FAILED 32 +#define AVG_ERR_MT_INIT 33 +#define AVG_ERR_DEBUG_CONTEXT_FAILED 34 + +namespace avg { + +class AVG_API Exception: public std::exception +{ + public: + Exception(int code, const std::string& sErr = ""); + Exception(const Exception& ex); + virtual ~Exception() throw(); + virtual int getCode() const; + virtual const std::string& getStr() const; + virtual const char* what() const throw(); + + private: + int m_Code; + std::string m_sErr; +}; + +void AVG_API debugBreak(); +void AVG_API avgAssert(bool b, const char * pszFile, int line, const char * pszReason=0); + +#define AVG_ASSERT(b) avgAssert((b) != 0, __FILE__, __LINE__); +#define AVG_ASSERT_MSG(b, pszReason) avgAssert((b) != 0, __FILE__, __LINE__, pszReason); + +} + +#endif diff --git a/src/base/FileHelper.cpp b/src/base/FileHelper.cpp new file mode 100644 index 0000000..d9221c4 --- /dev/null +++ b/src/base/FileHelper.cpp @@ -0,0 +1,164 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "FileHelper.h" +#include "Exception.h" + +#ifndef _WIN32 +#include <libgen.h> +#else +#include <direct.h> +#endif +#include <stdio.h> +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#include <vector> +#include <map> +#include <cstring> +#include <iostream> +#include <fstream> + +using namespace std; + +namespace avg { + +string getPath(const string& sFilename) +{ + if (sFilename.length() > 0 && sFilename.at(sFilename.length()-1) == '/') { + return sFilename; + } +#ifdef _WIN32 + int pos = int(sFilename.find_last_of("\\/")); + string dirName; + if (pos >= 0) { + dirName = sFilename.substr(0, pos+1); + } else { + dirName = sFilename; + } +#else + char * pszBuffer = strdup(sFilename.c_str()); + + string dirName(dirname(pszBuffer)); + free(pszBuffer); + dirName += "/"; +#endif + + return dirName; +} + +string getFilenamePart(const string& sFilename) +{ + if (sFilename.find_last_of("\\/") == 0) { + return sFilename; + } +#ifdef _WIN32 + int pos = int(sFilename.find_last_of("\\/")); + string BaseName(sFilename.substr(pos+1)); +#else + char * pszBuffer = strdup(sFilename.c_str()); + + string BaseName(basename(pszBuffer)); + free(pszBuffer); +#endif + + return BaseName; +} + +string getExtension(const string& sFilename) +{ + int pos = int(sFilename.find_last_of(".")); + if (pos == 0) { + return ""; + } else { + return sFilename.substr(pos+1); + } +} + +string getCWD() +{ + + char szBuf[1024]; +#ifdef _WIN32 + char * pBuf = _getcwd(szBuf, 1024); +#else + char * pBuf = getcwd(szBuf, 1024); +#endif + return string(pBuf)+"/"; +} + +bool isAbsPath(const std::string& path) +{ +#ifdef _WIN32 + return ((path.length() != 0) && path[1] == ':') || path[0] == '\\' || path[0] == '/'; +#else + return path[0] == '/'; +#endif + +} + +bool fileExists(const string& sFilename) +{ + struct stat myStat; + return stat(sFilename.c_str(), &myStat) != -1; +} + +void readWholeFile(const string& sFilename, string& sContent) +{ + ifstream file(sFilename.c_str()); + if (!file) { + throw Exception(AVG_ERR_FILEIO, "Opening "+sFilename+ + " for reading failed."); + } + vector<char> buffer(65536); + sContent.resize(0); + while (file) { + file.read(&(*buffer.begin()), (streamsize)(buffer.size())); + sContent.append(&(*buffer.begin()), (unsigned)file.gcount()); + } + if (!file.eof() || file.bad()) { + throw Exception(AVG_ERR_FILEIO, "Reading "+sFilename+ + " failed."); + } +} + +void writeWholeFile(const string& sFilename, const string& sContent) +{ + ofstream outFile(sFilename.c_str()); + if (!outFile) { + throw Exception(AVG_ERR_FILEIO, "Opening "+sFilename+ + " for writing failed."); + } + outFile << sContent; +} + + +void copyFile(const string& sSourceFile, const string& sDestFile) +{ + string sData; + + readWholeFile(sSourceFile, sData); + writeWholeFile(sDestFile, sData); +} + +} diff --git a/src/base/FileHelper.h b/src/base/FileHelper.h new file mode 100644 index 0000000..f367d0b --- /dev/null +++ b/src/base/FileHelper.h @@ -0,0 +1,53 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _FileHelper_H_ +#define _FileHelper_H_ + +#include "../api.h" +#include <string> + +namespace avg { + +std::string AVG_API getPath(const std::string& sFilename); +std::string AVG_API getFilenamePart(const std::string& sFilename); +std::string AVG_API getExtension(const std::string& sFilename); +std::string AVG_API getCWD(); + +bool AVG_API isAbsPath(const std::string& path); + +bool AVG_API fileExists(const std::string& sFilename); + +void AVG_API readWholeFile(const std::string& sFilename, std::string& sContents); + +void AVG_API writeWholeFile(const std::string& sFilename, const std::string& sContent); + +void AVG_API copyFile(const std::string& sSourceFile, const std::string& sDestFile); + + +#ifdef WIN32 +#define unlink _unlink +#endif + +} + +#endif + diff --git a/src/base/GLMHelper.cpp b/src/base/GLMHelper.cpp new file mode 100644 index 0000000..e4b0f43 --- /dev/null +++ b/src/base/GLMHelper.cpp @@ -0,0 +1,183 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "GLMHelper.h" +#include "StringHelper.h" +#include "MathHelper.h" + +#include "../glm/gtx/rotate_vector.hpp" + +using namespace std; + +namespace avg { + +glm::vec2 getRotated(const glm::vec2& vec, float angle) +{ + return glm::rotate(vec, angle*180/PI); +} + +glm::vec2 getRotatedPivot(const glm::vec2& vec, float angle, const glm::vec2& pivot) +{ + // translate pivot to origin + glm::vec2 translated = vec - pivot; + + // calculate rotated coordinates about the origin + glm::vec2 rotated = glm::rotate(translated, angle*180/PI); + + // re-translate pivot to original position + rotated += pivot; + + return rotated; +} + +float getAngle(const glm::vec2& vec) +{ + return float(atan2(double(vec.y), double(vec.x))); +} + +glm::vec2 fromPolar(float angle, float radius) +{ + return glm::vec2(cos(angle)*radius, sin(angle)*radius); +} + +template<class NUM> +bool almostEqual(const glm::detail::tvec2<NUM>& v1, const glm::detail::tvec2<NUM>& v2) +{ + return (fabs(v1.x-v2.x)+fabs(v1.y-v2.y)) < 0.0001; +} + +template<class NUM> +bool almostEqual(const glm::detail::tvec4<NUM>& v1, const glm::detail::tvec4<NUM>& v2) +{ + return (fabs(v1.x-v2.x)+fabs(v1.y-v2.y)+fabs(v1.z-v2.z)+fabs(v1.w-v2.w)) < 0.0001; +} + +template<class NUM> +std::ostream& operator<<( std::ostream& os, const glm::detail::tvec2<NUM> &v) +{ + os << "(" << v.x << "," << v.y << ")"; + return os; +} + +template<class NUM> +std::ostream& operator<<( std::ostream& os, const glm::detail::tvec3<NUM> &v) +{ + os << "(" << v.x << "," << v.y << "," << v.z << ")"; + return os; +} + +template<class NUM> +std::ostream& operator<<( std::ostream& os, const glm::detail::tvec4<NUM> &v) +{ + os << "(" << v.x << "," << v.y << "," << v.z << ", " << v.a << ")"; + return os; +} + +template<class NUM> +std::ostream& operator<<( std::ostream& os, const glm::detail::tmat4x4<NUM> &m) +{ + os << "(" << m[0] << ", " << endl << + m[1] << ", " << endl << + m[2] << ", " << endl << + m[3] << ", " << endl << ")"; + return os; +} + +template<class NUM> +std::istream& operator>>(std::istream& is, glm::detail::tvec2<NUM>& p) +{ + skipToken(is, '('); + is >> p.x; + skipToken(is, ','); + is >> p.y; + skipToken(is, ')'); + return is; +} + +template<class NUM> +std::istream& operator>>(std::istream& is, glm::detail::tvec3<NUM>& p) +{ + skipToken(is, '('); + is >> p.x; + skipToken(is, ','); + is >> p.y; + skipToken(is, ','); + is >> p.z; + skipToken(is, ')'); + return is; +} + +glm::vec2 stringToVec2(const std::string& s) +{ + glm::vec2 pt; + fromString(s, pt); + return pt; +} + +glm::vec3 stringToVec3(const std::string& s) +{ + glm::vec3 pt; + fromString(s, pt); + return pt; +} + +glm::ivec3 stringToIVec3(const std::string& s) +{ + glm::ivec3 pt; + fromString(s, pt); + return pt; +} + + +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec2<int> &p); +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec2<float> &p); +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec2<double> &p); + +template AVG_TEMPLATE_API std::istream& operator>>(std::istream& is, glm::detail::tvec2<int>& p); +template AVG_TEMPLATE_API std::istream& operator>>(std::istream& is, glm::detail::tvec2<float>& p); +template AVG_TEMPLATE_API std::istream& operator>>(std::istream& is, glm::detail::tvec2<double>& p); + +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec3<int> &p); +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec3<float> &p); +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec3<double> &p); + +template AVG_TEMPLATE_API std::istream& operator>>(std::istream& is, glm::detail::tvec3<int>& p); +template AVG_TEMPLATE_API std::istream& operator>>(std::istream& is, glm::detail::tvec3<float>& p); +template AVG_TEMPLATE_API std::istream& operator>>(std::istream& is, glm::detail::tvec3<double>& p); + +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec4<int> &p); +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec4<float> &p); +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tvec4<double> &p); + +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, const glm::detail::tmat4x4<float> &p); +template AVG_TEMPLATE_API std::ostream& operator<<(std::ostream& os, + const glm::detail::tmat4x4<double> &p); + +template AVG_TEMPLATE_API bool almostEqual(const glm::detail::tvec2<float>& v1, + const glm::detail::tvec2<float>& v2); +template AVG_TEMPLATE_API bool almostEqual(const glm::detail::tvec2<double>& v1, + const glm::detail::tvec2<double>& v2); +template AVG_TEMPLATE_API bool almostEqual(const glm::detail::tvec4<float>& v1, + const glm::detail::tvec4<float>& v2); +template AVG_TEMPLATE_API bool almostEqual(const glm::detail::tvec4<double>& v1, + const glm::detail::tvec4<double>& v2); +} + diff --git a/src/base/GLMHelper.h b/src/base/GLMHelper.h new file mode 100644 index 0000000..4af8991 --- /dev/null +++ b/src/base/GLMHelper.h @@ -0,0 +1,70 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _GLMHelper_H_ +#define _GLMHelper_H_ + +#include "../api.h" + +#include "../glm/glm.hpp" +#include "../glm/gtc/matrix_transform.hpp" +#include "../glm/gtc/type_ptr.hpp" + +#include <iostream> +#include <vector> + +namespace avg { + +glm::vec2 getRotated(const glm::vec2& vec, float angle); +glm::vec2 getRotatedPivot(const glm::vec2& vec, float angle, + const glm::vec2& pivot=glm::vec2(0,0)); +float getAngle(const glm::vec2& vec); +glm::vec2 fromPolar(float angle, float radius); + +template<class NUM> +bool almostEqual(const glm::detail::tvec2<NUM>& v1, const glm::detail::tvec2<NUM>& v2); +template<class NUM> +bool almostEqual(const glm::detail::tvec4<NUM>& v1, const glm::detail::tvec4<NUM>& v2); + +template<class NUM> +std::ostream& operator<<(std::ostream& os, const glm::detail::tvec2<NUM> &v); +template<class NUM> +std::ostream& operator<<(std::ostream& os, const glm::detail::tvec3<NUM> &v); +template<class NUM> +std::ostream& operator<<(std::ostream& os, const glm::detail::tvec4<NUM> &v); +template<class NUM> +std::ostream& operator<<(std::ostream& os, const glm::detail::tmat4x4<NUM> &v); + +template<class NUM> +std::istream& operator>>(std::istream& is, glm::detail::tvec2<NUM>& p); +template<class NUM> +std::istream& operator>>(std::istream& is, glm::detail::tvec3<NUM>& p); + +typedef glm::ivec2 IntPoint; +typedef std::vector<glm::vec2> Vec2Vector; + +glm::vec2 stringToVec2(const std::string& s); +glm::vec3 stringToVec3(const std::string& s); +glm::ivec3 stringToIVec3(const std::string& s); + +} + +#endif diff --git a/src/base/GeomHelper.cpp b/src/base/GeomHelper.cpp new file mode 100644 index 0000000..da167ad --- /dev/null +++ b/src/base/GeomHelper.cpp @@ -0,0 +1,178 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "GeomHelper.h" + +#include <math.h> +#include <iostream> + +using namespace std; + +namespace avg { + +LineSegment::LineSegment(const glm::vec2& pt0, const glm::vec2& pt1) + : p0(pt0), + p1(pt1) +{ +} + +bool LineSegment::isPointOver(const glm::vec2& pt) +{ + glm::vec2 c = pt - p0; + glm::vec2 v = (p1 - p0); + float d = glm::length(v); + v /= d; + float t = glm::dot(v, c); + + return (t >= 0 && t <= d); +} + +// Code adapted from Antonio, Franklin, "Faster Line Segment Intersection," +// Graphics Gems III (David Kirk, ed.), Academic Press, pp. 199-202, 1992. +bool lineSegmentsIntersect(const LineSegment& l0, const LineSegment& l1) +{ + float xdiff0 = l0.p1.x-l0.p0.x; + float xdiff1 = l1.p0.x-l1.p1.x; + + float x1lo, x1hi; + + /* X bound box test*/ + if (xdiff0 < 0) { + x1lo=l0.p1.x; + x1hi=l0.p0.x; + } else { + x1hi=l0.p1.x; + x1lo=l0.p0.x; + } + if (xdiff1 > 0) { + if (x1hi < l1.p1.x || l1.p0.x < x1lo) { + return false; + } + } else { + if (x1hi < l1.p0.x || l1.p1.x < x1lo) { + return false; + } + } + + float ydiff0 = l0.p1.y-l0.p0.y; + float ydiff1 = l1.p0.y-l1.p1.y; + + float y1lo, y1hi; + + /* Y bound box test*/ + if (ydiff0 < 0) { + y1lo=l0.p1.y; + y1hi=l0.p0.y; + } else { + y1hi=l0.p1.y; + y1lo=l0.p0.y; + } + if (ydiff1 > 0) { + if (y1hi < l1.p1.y || l1.p0.y < y1lo) { + return false; + } + } else { + if (y1hi < l1.p0.y || l1.p1.y < y1lo) { + return false; + } + } + + float Cx = l0.p0.x-l1.p0.x; + float Cy = l0.p0.y-l1.p0.y; + float d = ydiff1*Cx - xdiff1*Cy; /* alpha numerator*/ + float f = ydiff0*xdiff1 - xdiff0*ydiff1; /* both denominator*/ + if (f > 0) { /* alpha tests*/ + if (d < 0 || d > f) { + return false; + } + } else { + if (d > 0 || d < f) { + return false; + } + } + + float e = xdiff0*Cy - ydiff0*Cx; /* beta numerator*/ + if(f > 0) { /* beta tests*/ + if (e < 0 || e > f) { + return false; + } + } else { + if (e > 0 || e < f) { + return false; + } + } + + if (f == 0) { + // Theoretically, lines could still intersect in this case, but we don't care + // because given numerical inaccuracies, the result is random anyway :-). + return false; + } + +// /*compute intersection coordinates*/ +// float num = d*xdiff0; /* numerator */ +// offset = SAME_SIGNS(num,f) ? f/2 : -f/2; /* round direction*/ +// *x = x1 + (num+offset) / f; /* intersection x */ +// +// num = d*ydiff0; +// offset = SAME_SIGNS(num,f) ? f/2 : -f/2; +// *y = y1 + (num+offset) / f; /* intersection y */ + + return true; +} + +// Original code from: +// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html. +// Precomputing a bounding box for the polygon would speed this up a lot, +// but the function hasn't shown up on any profiles so far. +bool pointInPolygon(const glm::vec2& pt, const vector<glm::vec2>& poly) +{ + if (poly.size() < 3) { + return false; + } + bool bPtInPoly = false; + for (unsigned i = 0, j = poly.size()-1; i < poly.size(); j = i++) { + if (((poly[i].y > pt.y) != (poly[j].y > pt.y)) && + (pt.x < (poly[j].x-poly[i].x)*(pt.y-poly[i].y) / (poly[j].y-poly[i].y) + +poly[i].x)) + { + bPtInPoly = !bPtInPoly; + } + } + return bPtInPoly; +} + +glm::vec2 getLineLineIntersection(const glm::vec2& p1, const glm::vec2& v1, + const glm::vec2& p2, const glm::vec2& v2) +{ + float denom = v2.y*v1.x-v2.x*v1.y; + if (fabs(denom) < 0.0000001) { + // If the lines are parallel or coincident, we just return p2! + return p2; + } + float numer = v2.x*(p1.y-p2.y) - v2.y*(p1.x-p2.x); + float ua = numer/denom; + + return p1+ua*v1; + +} + + +} diff --git a/src/base/GeomHelper.h b/src/base/GeomHelper.h new file mode 100644 index 0000000..5774231 --- /dev/null +++ b/src/base/GeomHelper.h @@ -0,0 +1,51 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _GeomHelper_H_ +#define _GeomHelper_H_ + +#include "../api.h" + +#include "../glm/glm.hpp" + +#include <vector> + +namespace avg { + +struct AVG_API LineSegment { +public: + LineSegment(const glm::vec2& pt0, const glm::vec2& pt1); + glm::vec2 p0; + glm::vec2 p1; + + bool isPointOver(const glm::vec2& pt); +}; + +bool AVG_API lineSegmentsIntersect(const LineSegment& l0, const LineSegment& l1); + +bool AVG_API pointInPolygon(const glm::vec2& pt, const std::vector<glm::vec2>& poly); + +glm::vec2 AVG_API getLineLineIntersection(const glm::vec2& p1, const glm::vec2& v1, + const glm::vec2& p2, const glm::vec2& v2); + +} +#endif + diff --git a/src/base/IFrameEndListener.h b/src/base/IFrameEndListener.h new file mode 100644 index 0000000..6147dbe --- /dev/null +++ b/src/base/IFrameEndListener.h @@ -0,0 +1,37 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _IFrameEndListener_H_ +#define _IFrameEndListener_H_ + +#include "../api.h" + +namespace avg { + +class AVG_API IFrameEndListener { +public: + virtual ~IFrameEndListener() {}; + virtual void onFrameEnd() = 0; +}; + +} + +#endif diff --git a/src/base/ILogSink.h b/src/base/ILogSink.h new file mode 100644 index 0000000..de4c1da --- /dev/null +++ b/src/base/ILogSink.h @@ -0,0 +1,53 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de + +#ifndef _ILOGHANDLER_H_ +#define _ILOGHANDLER_H_ + +#include "UTF8String.h" + +#ifdef _WIN32 +#include <time.h> +#else +#include <sys/time.h> +#endif + +#include <boost/shared_ptr.hpp> + +using namespace std; + +namespace avg{ + +typedef unsigned severity_t; +typedef UTF8String category_t; + +class AVG_API ILogSink +{ +public: + virtual void logMessage(const tm* pTime, unsigned millis, const category_t& category, + severity_t severity, const UTF8String& sMsg) = 0; + +}; + +typedef boost::shared_ptr<ILogSink> LogSinkPtr; + +} + +#endif diff --git a/src/base/IPlaybackEndListener.h b/src/base/IPlaybackEndListener.h new file mode 100644 index 0000000..f505177 --- /dev/null +++ b/src/base/IPlaybackEndListener.h @@ -0,0 +1,38 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _IPlaybackEndListener_H_ +#define _IPlaybackEndListener_H_ + +#include "../api.h" + +namespace avg { + +class AVG_API IPlaybackEndListener { +public: + virtual ~IPlaybackEndListener() {}; + virtual void onPlaybackEnd() = 0; +}; + +} + +#endif + diff --git a/src/base/IPreRenderListener.h b/src/base/IPreRenderListener.h new file mode 100644 index 0000000..32c244e --- /dev/null +++ b/src/base/IPreRenderListener.h @@ -0,0 +1,35 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _IPreRenderListener_H_ +#define _IPreRenderListener_H_ + +namespace avg { + +class AVG_API IPreRenderListener { +public: + virtual ~IPreRenderListener() {}; + virtual void onPreRender() = 0; +}; + +} + +#endif diff --git a/src/base/Logger.cpp b/src/base/Logger.cpp new file mode 100644 index 0000000..dd7efe1 --- /dev/null +++ b/src/base/Logger.cpp @@ -0,0 +1,280 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "Logger.h" +#include "Exception.h" +#include "StandardLogSink.h" +#include "OSHelper.h" + +#include <boost/algorithm/string.hpp> + +#ifdef _WIN32 +#include <Winsock2.h> +#include <time.h> +#include <Mmsystem.h> +#undef ERROR +#else +#include <sys/time.h> +#include <syslog.h> +#endif +#include <iostream> +#include <iomanip> + +using namespace std; +namespace ba = boost::algorithm; + +namespace avg { + const severity_t Logger::severity::CRITICAL = 50; + const severity_t Logger::severity::ERROR = 40; + const severity_t Logger::severity::WARNING = 30; + const severity_t Logger::severity::INFO = 20; + const severity_t Logger::severity::DEBUG = 10; + const severity_t Logger::severity::NONE = 0; + + const category_t Logger::category::NONE = UTF8String("NONE"); + const category_t Logger::category::PROFILE = UTF8String("PROFILE"); + const category_t Logger::category::PROFILE_VIDEO = UTF8String("PROFILE_V"); + const category_t Logger::category::EVENTS = UTF8String("EVENTS"); + const category_t Logger::category::CONFIG = UTF8String("CONFIG"); + const category_t Logger::category::MEMORY = UTF8String("MEMORY"); + const category_t Logger::category::APP = UTF8String("APP"); + const category_t Logger::category::PLUGIN = UTF8String("PLUGIN"); + const category_t Logger::category::PLAYER = UTF8String("PLAYER"); + const category_t Logger::category::SHADER = UTF8String("SHADER"); + const category_t Logger::category::DEPRECATION = UTF8String("DEPREC"); + +namespace { + Logger* s_pLogger = 0; + boost::mutex s_logMutex; + boost::mutex s_traceMutex; + boost::mutex s_sinkMutex; + boost::mutex s_removeStdSinkMutex; +} + +boost::mutex Logger::m_CategoryMutex; + +Logger * Logger::get() +{ + lock_guard lock(s_logMutex); + if (!s_pLogger) { + s_pLogger = new Logger; + } + return s_pLogger; +} + +Logger::Logger() +{ + m_Severity = severity::WARNING; + string sEnvSeverity; + bool bEnvSeveritySet = getEnv("AVG_LOG_SEVERITY", sEnvSeverity); + if(bEnvSeveritySet) { + m_Severity = Logger::stringToSeverity(sEnvSeverity); + } + setupCategory(); + + string sEnvCategories; + bool bEnvSet = getEnv("AVG_LOG_CATEGORIES", sEnvCategories); + if (bEnvSet) { + vector<string> sCategories; + ba::split(sCategories, sEnvCategories, ba::is_any_of(" "), ba::token_compress_on); + vector<string>::iterator it; + for(it=sCategories.begin(); it!=sCategories.end(); it++) { + string::size_type pos = (*it).find(":"); + string sCategory; + string sSeverity = "NONE"; + if(pos == string::npos) { + sCategory = *it; + } else { + vector<string> tmpValues; + ba::split( tmpValues, *it, ba::is_any_of(":"), ba::token_compress_on); + sCategory = tmpValues.at(0); + sSeverity = tmpValues.at(1); + } + severity_t severity = stringToSeverity(sSeverity); + configureCategory(sCategory, severity); + } + } + + string sDummy; + bool bEnvOmitStdErr = getEnv("AVG_LOG_OMIT_STDERR", sDummy); + if (!bEnvOmitStdErr) { + m_pStdSink = LogSinkPtr(new StandardLogSink); + addLogSink(m_pStdSink); + } +} + +Logger::~Logger() +{ +} + +void Logger::addLogSink(const LogSinkPtr& logSink) +{ + lock_guard lock(s_sinkMutex); + m_pSinks.push_back(logSink); +} + +void Logger::removeLogSink(const LogSinkPtr& logSink) +{ + lock_guard lock(s_sinkMutex); + std::vector<LogSinkPtr>::iterator it; + it = find(m_pSinks.begin(), m_pSinks.end(), logSink); + if ( it != m_pSinks.end() ) { + m_pSinks.erase(it); + } +} + +void Logger::removeStdLogSink() +{ + lock_guard lock(s_removeStdSinkMutex); + if ( m_pStdSink.get()) { + removeLogSink(m_pStdSink); + m_pStdSink = LogSinkPtr(); + } +} + +category_t Logger::configureCategory(category_t category, severity_t severity) +{ + lock_guard lock(m_CategoryMutex); + severity = (severity == Logger::severity::NONE) ? m_Severity : severity; + UTF8String sCategory = boost::to_upper_copy(string(category)); + CatToSeverityMap::iterator it; + it = m_CategorySeverities.find(sCategory); + if ( it != m_CategorySeverities.end()) { + m_CategorySeverities.erase(sCategory); + } + pair<const category_t, const severity_t> element(sCategory, severity); + m_CategorySeverities.insert(element); + return sCategory; +} + +CatToSeverityMap Logger::getCategories() +{ + return m_CategorySeverities; +} + +void Logger::trace(const UTF8String& sMsg, const category_t& category, + severity_t severity) const +{ + lock_guard lock(s_traceMutex); + struct tm* pTime; + #ifdef _WIN32 + __int64 now; + _time64(&now); + pTime = _localtime64(&now); + DWORD tms = timeGetTime(); + unsigned millis = unsigned(tms % 1000); + #else + struct timeval time; + gettimeofday(&time, NULL); + pTime = localtime(&time.tv_sec); + unsigned millis = time.tv_usec/1000; + #endif + lock_guard lockHandler(s_sinkMutex); + std::vector<LogSinkPtr>::const_iterator it; + for(it=m_pSinks.begin(); it!=m_pSinks.end(); ++it){ + (*it)->logMessage(pTime, millis, category, severity, sMsg); + } +} + +void Logger::logDebug(const UTF8String& msg, const category_t& category) const +{ + log(msg, category, Logger::severity::DEBUG); +} + +void Logger::logInfo(const UTF8String& msg, const category_t& category) const +{ + log(msg, category, Logger::severity::INFO); +} + +void Logger::logWarning(const UTF8String& msg, const category_t& category) const +{ + log(msg, category, Logger::severity::WARNING); +} + +void Logger::logError(const UTF8String& msg, const category_t& category) const +{ + log(msg, category, Logger::severity::ERROR); +} + +void Logger::logCritical(const UTF8String& msg, const category_t& category) const +{ + log(msg, category, Logger::severity::CRITICAL); +} + +void Logger::log(const UTF8String& msg, const category_t& category, + severity_t severity) const +{ + if(shouldLog(category, severity)) { + Logger::trace(msg, category, severity); + } +} + +void Logger::setupCategory() +{ + configureCategory(category::NONE); + configureCategory(category::PROFILE); + configureCategory(category::PROFILE_VIDEO); + configureCategory(category::EVENTS); + configureCategory(category::CONFIG); + configureCategory(category::MEMORY); + configureCategory(category::APP); + configureCategory(category::PLUGIN); + configureCategory(category::PLAYER); + configureCategory(category::SHADER); + configureCategory(category::DEPRECATION); +} + +severity_t Logger::stringToSeverity(const string& sSeverity) +{ + string severity = boost::to_upper_copy(string(sSeverity)); + if (severity == "CRIT") { + return Logger::severity::CRITICAL; + } else if (severity == "ERR") { + return Logger::severity::ERROR; + } else if (severity == "WARN") { + return Logger::severity::WARNING; + } else if (severity == "INFO") { + return Logger::severity::INFO; + } else if (severity == "DBG") { + return Logger::severity::DEBUG; + } else if (severity == "NONE") { + return Logger::severity::NONE; + } + throw Exception(AVG_ERR_INVALID_ARGS, severity + " is an invalid log severity"); +} + +const char * Logger::severityToString(severity_t severity) +{ + if(severity == Logger::severity::CRITICAL) { + return "CRIT"; + } else if(severity == Logger::severity::ERROR) { + return "ERR"; + } else if(severity == Logger::severity::WARNING) { + return "WARN"; + } else if(severity == Logger::severity::INFO) { + return "INFO"; + } else if(severity == Logger::severity::DEBUG) { + return "DBG"; + } + throw Exception(AVG_ERR_UNKNOWN, "Unkown log severity"); +} + +} diff --git a/src/base/Logger.h b/src/base/Logger.h new file mode 100644 index 0000000..197c0c2 --- /dev/null +++ b/src/base/Logger.h @@ -0,0 +1,154 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Logger_H_ +#define _Logger_H_ + +#include "Exception.h" +#include "ILogSink.h" +#include "UTF8String.h" +#include "ThreadHelper.h" +#include "../api.h" + +#include <boost/noncopyable.hpp> +#include <boost/functional/hash.hpp> +#include <boost/unordered_map.hpp> + +#include <string> +#include <vector> +#include <sstream> + +#ifdef ERROR +#undef ERROR +#endif + +namespace avg { + +typedef boost::unordered_map< const category_t, const severity_t > CatToSeverityMap; + +#ifdef _WIN32 +// non dll-interface class used as base for dll-interface class +#pragma warning(disable:4275) +#endif +class AVG_API Logger: private boost::noncopyable { +public: + struct AVG_API severity + { + static const severity_t CRITICAL; + static const severity_t ERROR; + static const severity_t WARNING; + static const severity_t INFO; + static const severity_t DEBUG; + static const severity_t NONE; + }; + + struct AVG_API category + { + static const category_t NONE; + static const category_t PROFILE; + static const category_t PROFILE_VIDEO; + static const category_t EVENTS; + static const category_t CONFIG; + static const category_t MEMORY; + static const category_t APP; + static const category_t PLUGIN; + static const category_t PLAYER; + static const category_t SHADER; + static const category_t DEPRECATION; + }; + + static Logger* get(); + virtual ~Logger(); + + static severity_t stringToSeverity(const string& sSeverity); + static const char * severityToString(const severity_t severity); + + void addLogSink(const LogSinkPtr& logSink); + void removeLogSink(const LogSinkPtr& logSink); + void removeStdLogSink(); + + category_t configureCategory(category_t category, + severity_t severity=severity::NONE); + CatToSeverityMap getCategories(); + + void trace(const UTF8String& sMsg, const category_t& category, + severity_t severity) const; + void logDebug(const UTF8String& msg, + const category_t& category=category::APP) const; + void logInfo(const UTF8String& msg, + const category_t& category=category::APP) const; + void logWarning(const UTF8String& msg, + const category_t& category=category::APP) const; + void logError(const UTF8String& msg, + const category_t& category=category::APP) const; + void logCritical(const UTF8String& msg, + const category_t& category=category::APP) const; + void log(const UTF8String& msg, const category_t& category=category::APP, + severity_t severity=severity::INFO) const; + + inline bool shouldLog(const category_t& category, severity_t severity) const { + lock_guard lock(m_CategoryMutex); + try { + severity_t targetSeverity = m_CategorySeverities.at(category); + return (targetSeverity <= severity); + } catch (out_of_range e){ + string msg("Unknown category: " + category); + throw Exception(AVG_ERR_INVALID_ARGS, msg); + } + } + +private: + Logger(); + void setupCategory(); + + std::vector<LogSinkPtr> m_pSinks; + LogSinkPtr m_pStdSink; + CatToSeverityMap m_CategorySeverities; + severity_t m_Severity; + static boost::mutex m_CategoryMutex; +}; + +#define AVG_TRACE(category, severity, sMsg) { \ +if (Logger::get()->shouldLog(category, severity)) { \ + std::stringstream tmp(std::stringstream::in | std::stringstream::out); \ + tmp << sMsg; \ + Logger::get()->trace(tmp.str(), category, severity); \ + }\ +}\ + +#define AVG_LOG_ERROR(sMsg){ \ + AVG_TRACE(Logger::category::NONE, Logger::severity::ERROR, sMsg); \ +}\ + +#define AVG_LOG_WARNING(sMsg){ \ + AVG_TRACE(Logger::category::NONE, Logger::severity::WARNING, sMsg); \ +}\ + +#define AVG_LOG_INFO(sMsg){ \ + AVG_TRACE(Logger::category::NONE, Logger::severity::INFO, sMsg); \ +}\ + +#define AVG_LOG_DEBUG(sMsg){ \ + AVG_TRACE(Logger::category::NONE, Logger::severity::DEBUG, sMsg); \ +}\ + +} +#endif diff --git a/src/base/Makefile.am b/src/base/Makefile.am new file mode 100644 index 0000000..ce995f2 --- /dev/null +++ b/src/base/Makefile.am @@ -0,0 +1,35 @@ +SUBDIRS = triangulate + +AM_CPPFLAGS = -I.. @XML2_CFLAGS@ @PTHREAD_CFLAGS@ +ALL_H = FileHelper.h Exception.h Logger.h ConfigMgr.h ObjectCounter.h \ + XMLHelper.h TimeSource.h ProfilingZone.h ThreadProfiler.h \ + ScopeTimer.h IFrameEndListener.h IPreRenderListener.h IPlaybackEndListener.h \ + Test.h TestSuite.h OSHelper.h Queue.h WorkerThread.h Command.h ObjectCounter.h \ + Rect.h Directory.h DirEntry.h StringHelper.h MathHelper.h GeomHelper.h \ + CubicSpline.h BezierCurve.h UTF8String.h Triangle.h DAG.h \ + WideLine.h DlfcnWrapper.h Signal.h Backtrace.h \ + CmdQueue.h ProfilingZoneID.h GLMHelper.h StandardLogSink.h ILogSink.h \ + ThreadHelper.h + +TESTS = testbase + +EXTRA_DIST = DlfcnWrapper.cpp + +noinst_LTLIBRARIES = libbase.la +libbase_la_SOURCES = FileHelper.cpp Exception.cpp Logger.cpp \ + ConfigMgr.cpp XMLHelper.cpp TimeSource.cpp OSHelper.cpp \ + ProfilingZone.cpp ThreadProfiler.cpp ScopeTimer.cpp Test.cpp \ + TestSuite.cpp ObjectCounter.cpp Directory.cpp DirEntry.cpp \ + StringHelper.cpp MathHelper.cpp GeomHelper.cpp CubicSpline.cpp \ + BezierCurve.cpp UTF8String.cpp Triangle.cpp DAG.cpp WideLine.cpp \ + Backtrace.cpp ProfilingZoneID.cpp GLMHelper.cpp \ + WorkerThread.cpp StandardLogSink.cpp ThreadHelper.cpp \ + $(ALL_H) +libbase_a_CXXFLAGS = -Wno-format-y2k + +noinst_PROGRAMS = testbase +testbase_SOURCES = testbase.cpp $(ALL_H) +testbase_LDADD = ./libbase.la ./triangulate/libtriangulate.la \ + @BOOST_THREAD_LIBS@ @XML2_LIBS@ @PTHREAD_LIBS@ +# -rdynamic needed only for testBacktrace to work under linux. +testbase_LDFLAGS = -rdynamic diff --git a/src/base/MathHelper.cpp b/src/base/MathHelper.cpp new file mode 100644 index 0000000..388859d --- /dev/null +++ b/src/base/MathHelper.cpp @@ -0,0 +1,78 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "MathHelper.h" + +#include <math.h> +#include <iostream> + +using namespace std; + +namespace avg { + +bool ispow2(int n) +{ + return ((n & (n-1)) == 0); +} + +int nextpow2(int n) +{ + n--; + n |= n >> 1; // handle 2 bit numbers + n |= n >> 2; // handle 4 bit numbers + n |= n >> 4; // handle 8 bit numbers + n |= n >> 8; // handle 16 bit numbers + n |= n >> 16; // handle 32 bit numbers + n++; + return n; +} + +int safeCeil(float d) +{ + if (fabs(d-int(d)) < EPSILON) { + return int(d); + } else { + return int(d)+1; + } +} + +float invSqrt(float x) +{ +#if 0 + // TODO: This gives incorrect results on Athlon X2, gcc 4.2. + float xhalf = 0.5f*x; + int i = *(int*)&x; // get bits for floating value + i = 0x5f3759d5 - (i>>1); // give initial guess y0 + x = *(float*)&i; // convert bits back to float + x *= 1.5f - xhalf*x*x; // newton step, repeating this step + // increases accuracy + x *= 1.5f - xhalf*x*x; + return x; +#endif + return 1/sqrt(x); +} + +bool almostEqual(float d1, float d2, float epsilon) +{ + return (fabs(d1-d2)<epsilon); +} + +} diff --git a/src/base/MathHelper.h b/src/base/MathHelper.h new file mode 100644 index 0000000..587ff2c --- /dev/null +++ b/src/base/MathHelper.h @@ -0,0 +1,93 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _MathHelper_H_ +#define _MathHelper_H_ + +#include "../api.h" +#include <vector> +#include <set> + +#include <math.h> +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace avg { + +static const float PI = 3.14159265358979323846f; +static const float EPSILON = 0.00001f; + +bool ispow2(int n); + +int nextpow2(int n); + +int safeCeil(float d); + +bool almostEqual(float d1, float d2, float epsilon=EPSILON); + +float invSqrt(float x); + +template<class T> +T sqr(T d) +{ + return d*d; +} + +template<class T> +int sgn(T val) +{ + return int(val/fabs(val)); +} + +template<class T> +std::vector<T> vectorFromCArray(int n, T* pData) +{ + std::vector<T> v; + for (int i=0; i<n; ++i) { + v.push_back(*(pData+i)); + } + return v; +} + +template<class T> +std::vector<std::vector<T> > vector2DFromCArray(int n, int m, T* pData) +{ + std::vector<std::vector<T> > v(4, std::vector<T>()); + for (int i=0; i<n; ++i) { + for (int j=0; j<m; ++j) { + v[i].push_back(*(pData+j+i*m)); + } + } + return v; +} + +#ifndef round +template<class T> +T round(T d) +{ + return floor(d + 0.5f); +} +#endif + +} +#endif + diff --git a/src/base/OSHelper.cpp b/src/base/OSHelper.cpp new file mode 100644 index 0000000..377e725 --- /dev/null +++ b/src/base/OSHelper.cpp @@ -0,0 +1,308 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "OSHelper.h" +#include "FileHelper.h" +#include "Logger.h" +#include "FileHelper.h" +#include "Exception.h" + +#if defined(_WIN32) +#include <windows.h> +#include <psapi.h> +#undef ERROR +#undef WARNING +#elif defined(__APPLE__) +#include <mach-o/dyld.h> +#include <mach/mach.h> +#include <sys/utsname.h> +#elif defined(__linux) +#include <fstream> +#include <unistd.h> +#include <string.h> +#endif + +#include <stdlib.h> +#include <iostream> +#include <cstdlib> + +using namespace std; + +namespace avg { + +#ifdef _WIN32 +string getWinErrMsg(unsigned err) +{ + LPVOID lpMsgBuf; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, + 0, NULL ); + string sMsg((char*)lpMsgBuf); + LocalFree(lpMsgBuf); + return sMsg; +} +#endif + +#if defined(__linux) +// Adapted from binreloc +static char * +_br_find_exe_for_symbol (const void *symbol) +{ + #define SIZE 1024 + FILE *f; + size_t address_string_len; + char *address_string, line[SIZE], *found; + + if (symbol == NULL) + return (char *) NULL; + + f = fopen ("/proc/self/maps", "r"); + if (f == NULL) + return (char *) NULL; + + address_string_len = 4; + address_string = (char *) malloc(address_string_len); + found = (char *) NULL; + + + while (!feof (f)) { + char *start_addr, *end_addr, *end_addr_end, *file; + void *start_addr_p, *end_addr_p; + size_t len; + + if (fgets (line, SIZE, f) == NULL) + break; + + /* Sanity check. */ + if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL) + continue; + + /* Parse line. */ + start_addr = line; + end_addr = strchr (line, '-'); + file = strchr (line, '/'); + + /* More sanity check. */ + if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-')) + continue; + + end_addr[0] = '\0'; + end_addr++; + end_addr_end = strchr (end_addr, ' '); + if (end_addr_end == NULL) + continue; + + end_addr_end[0] = '\0'; + len = strlen (file); + if (len == 0) + continue; + if (file[len - 1] == '\n') + file[len - 1] = '\0'; + + /* Get rid of "(deleted)" from the filename. */ + len = strlen (file); + if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0) + file[len - 10] = '\0'; + + /* I don't know whether this can happen but better safe than sorry. */ + len = strlen (start_addr); + if (len != strlen (end_addr)) + continue; + + + /* Transform the addresses into a string in the form of 0xdeadbeef, + * then transform that into a pointer. */ + if (address_string_len < len + 3) { + address_string_len = len + 3; + address_string = (char *) realloc (address_string, address_string_len); + } + + memcpy (address_string, "0x", 2); + memcpy (address_string + 2, start_addr, len); + address_string[2 + len] = '\0'; + sscanf (address_string, "%p", &start_addr_p); + + memcpy (address_string, "0x", 2); + memcpy (address_string + 2, end_addr, len); + address_string[2 + len] = '\0'; + sscanf (address_string, "%p", &end_addr_p); + + + if (symbol >= start_addr_p && symbol < end_addr_p) { + found = file; + break; + } + } + + free (address_string); + fclose (f); + + if (found == NULL) + return (char *) NULL; + else + return strdup (found); +} +#endif + +string getAvgLibPath() +{ +#if defined(_WIN32) + HMODULE hModule = GetModuleHandle("avg.pyd"); + char szFilename[1024]; + DWORD ok = GetModuleFileName(hModule, szFilename, sizeof(szFilename)); + if (ok == 0) { + AVG_LOG_ERROR("getAvgLibPath(): " << getWinErrMsg(GetLastError())); + exit(5); + } + string sPath=getPath(szFilename); + return sPath; +#elif defined(__APPLE__) + // We need to iterate through all images attached to the current executable + // and figure out which one is the one we are interested in. + uint32_t numImages = _dyld_image_count(); + for (uint32_t i=0; i<numImages; i++) { + const char * pszImageName = _dyld_get_image_name(i); + string sFilePart=getFilenamePart(pszImageName); + if (sFilePart == "avg.so" || sFilePart == "avg.0.so" + || sFilePart == "avg.0.0.0.so") + { + return getPath(pszImageName); + } + } + char path[1024]; + uint32_t pathLen = sizeof(path); + _NSGetExecutablePath(path, &pathLen); + return getPath(path); +#else + char* pszFilename; + pszFilename = _br_find_exe_for_symbol((const void *)""); + return pszFilename; +#endif +} + +bool getEnv(const string & sName, string & sVal) +{ + const char * pszVal = getenv(sName.c_str()); + if (pszVal) { + sVal = pszVal; + } + return (pszVal != 0); +} + +void setEnv(const string & sName, const string & sVal) +{ +#ifdef _WIN32 + SetEnvironmentVariable(sName.c_str(), sVal.c_str()); +#else + setenv(sName.c_str(), sVal.c_str(), true); +#endif +} + +size_t getMemoryUsage() +{ +#ifdef __APPLE__ + kern_return_t rc; + mach_port_t task; + rc = task_for_pid(mach_task_self(), getpid(), &task); + AVG_ASSERT(rc == KERN_SUCCESS); + struct task_basic_info taskInfo; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + rc = task_info(task, TASK_BASIC_INFO, (task_info_t)&taskInfo, &count); + AVG_ASSERT(rc == KERN_SUCCESS); + return taskInfo.resident_size; +#else +#ifdef _WIN32 + DWORD pid = GetCurrentProcessId(); + HANDLE hProcess; + PROCESS_MEMORY_COUNTERS pmc; + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + BOOL bOk = GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)); + CloseHandle(hProcess); + return pmc.WorkingSetSize; +#else + unsigned vmsize; + unsigned rssize; + // See 'man proc' for a documentation of this file's contents. + std::ifstream f("/proc/self/statm"); + f >> vmsize >> rssize; + return rssize*(size_t)(getpagesize()); +#endif +#endif +} + +std::string convertUTF8ToFilename(const std::string & sName) +{ +#ifdef _WIN32 + // Conversion from utf-8 to something windows can use: + // utf-8 long filename -> utf-16 long filename -> utf-16 short filename (8.3) + // -> utf-8 short filename (= ASCII short filename). + wchar_t wideString[2048]; + int err1 = MultiByteToWideChar(CP_UTF8, 0, sName.c_str(), sName.size()+1, + wideString, 2048); + if (err1 == 0) { + AVG_LOG_WARNING("Error in unicode conversion (MultiByteToWideChar): " << + getWinErrMsg(GetLastError())); + return sName; + } + wchar_t wideShortFName[2048]; + DWORD err2 = GetShortPathNameW(wideString, wideShortFName, 1024); + if (err2 != 0) { + char pShortName[1024]; + err1 = WideCharToMultiByte(CP_UTF8, 0, wideShortFName, -1, pShortName, + 1024, 0, 0); + if (err1 == 0) { + AVG_LOG_WARNING("Error in unicode conversion (MultiByteToWideChar): " << + getWinErrMsg(GetLastError())); + } + return pShortName; + } else { + return sName; + } +#else + return sName; +#endif +} + +#ifdef __APPLE__ +int reallyGetOSXMajorVersion() +{ + utsname sysInfo; + int rc = uname(&sysInfo); + AVG_ASSERT(rc == 0); +// cerr << sysInfo.sysname << ", " << sysInfo.nodename << ", " << sysInfo.release << +// ", " << sysInfo.version << ", " << sysInfo.machine << endl; + istringstream ss(sysInfo.release); + int major; + int minor; + int dot; + char c; + ss >> major >> c >> minor >> c >> dot; + return major; +} + +int getOSXMajorVersion() +{ + static int major = reallyGetOSXMajorVersion(); // only called once for speed reasons. + return major; +} +#endif +} diff --git a/src/base/OSHelper.h b/src/base/OSHelper.h new file mode 100644 index 0000000..6abda5a --- /dev/null +++ b/src/base/OSHelper.h @@ -0,0 +1,52 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _OSHelper_H_ +#define _OSHelper_H_ + +#include "../api.h" +#include <string> + +namespace avg { + +#ifdef _WIN32 +std::string getWinErrMsg(unsigned err); +#endif + +std::string getAvgLibPath(); + +bool getEnv(const std::string & sName, std::string & sVal); +void setEnv(const std::string & sName, const std::string & sVal); + +size_t getMemoryUsage(); + +// Converts a utf-8-encoded filename to something windows can use. +// Under other operating systems, returns the input string. +AVG_API std::string convertUTF8ToFilename(const std::string & sName); + +#ifdef __APPLE__ +int getOSXMajorVersion(); +#endif + +} + +#endif + diff --git a/src/base/ObjectCounter.cpp b/src/base/ObjectCounter.cpp new file mode 100644 index 0000000..e8136b7 --- /dev/null +++ b/src/base/ObjectCounter.cpp @@ -0,0 +1,187 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "ObjectCounter.h" +#include "Exception.h" +#include "Logger.h" + +#include <boost/thread/mutex.hpp> + +#include <iostream> +#include <sstream> +#include <vector> +#include <algorithm> + +#ifdef WIN32 +#include <windows.h> +#include <Dbghelp.h> +#else +#include <cxxabi.h> +#endif + +#define DEBUG_ALLOC 1 + +namespace avg { + +using namespace std; + +ObjectCounter* ObjectCounter::s_pObjectCounter = 0; +bool ObjectCounter::s_bDeleted = false; +boost::mutex * pCounterMutex; + +void deleteObjectCounter() +{ + delete ObjectCounter::s_pObjectCounter; + delete pCounterMutex; + ObjectCounter::s_pObjectCounter = 0; +} + +ObjectCounter::ObjectCounter() +{ +} + +ObjectCounter::~ObjectCounter() +{ + s_bDeleted = true; +} + +ObjectCounter * ObjectCounter::get() +{ + if (!s_pObjectCounter) { + if (s_bDeleted) { + // This is _after_ the deleteObjectCounter has been called. + return 0; + } else { + s_pObjectCounter = new ObjectCounter; + pCounterMutex = new boost::mutex; + atexit(deleteObjectCounter); + } + } + return s_pObjectCounter; +} + +void ObjectCounter::incRef(const std::type_info* pType) +{ +#ifdef DEBUG_ALLOC + lock_guard Lock(*pCounterMutex); + TypeMap::iterator MapEntry = m_TypeMap.find(pType); + if (MapEntry == m_TypeMap.end()) { + m_TypeMap[pType] = 1; + } else { + (MapEntry->second)++; + } +// cerr << "incRef " << demangle(pType->name()) << ":" << m_TypeMap[pType] << endl; +#endif +} + +void ObjectCounter::decRef(const std::type_info* pType) +{ +#ifdef DEBUG_ALLOC + if (!this) { + // This happens if there are counted static objects that are deleted after + // s_pObjectCounter has been deleted. + return; + } + lock_guard Lock(*pCounterMutex); + TypeMap::iterator MapEntry = m_TypeMap.find(pType); + if (MapEntry == m_TypeMap.end()) { + cerr << "ObjectCounter for " << demangle(pType->name()) + << " does not exist." << endl; + // Can't decref a type that hasn't been incref'd. + AVG_ASSERT(false); + } else { + (MapEntry->second)--; + if (MapEntry->second < 0) { + cerr << "ObjectCounter: refcount for " << + demangle(MapEntry->first->name()) << + " < 0" << endl; + AVG_ASSERT(false); + } + } +// cerr << "decRef " << demangle(pType->name()) << ":" << MapEntry->second << endl; +#endif +} + +int ObjectCounter::getCount(const std::type_info* pType) +{ + TypeMap::iterator MapEntry = m_TypeMap.find(pType); + if (MapEntry == m_TypeMap.end()) { + return 0; + } else { + return MapEntry->second; + } + +} + +std::string ObjectCounter::dump() +{ + stringstream ss; + ss << "Object dump: " << endl; + TypeMap::iterator it; + vector<string> strings; + for (it = m_TypeMap.begin(); it != m_TypeMap.end(); ++it) { + stringstream tempStream; + if (it->second > 0) { + tempStream << " " << demangle(it->first->name()) << ": " << it->second; + strings.push_back(tempStream.str()); + } + } + sort(strings.begin(), strings.end()); + for (vector<string>::iterator it=strings.begin(); it != strings.end(); ++it) { + ss << *it << endl; + } + return ss.str(); +} + +string ObjectCounter::demangle(string s) +{ + int rc; + string sResult; +#ifdef _WIN32 + char szDemangledName[2048]; + rc = int(UnDecorateSymbolName(s.c_str(), szDemangledName, sizeof(szDemangledName), + UNDNAME_COMPLETE)); + if (rc) { + sResult = szDemangledName; + } else { + int error = GetLastError(); + printf("UnDecorateSymbolName returned error %d\n", error); + sResult = s; + } +#else + char * pszDemangled = abi::__cxa_demangle(s.c_str(), 0, 0, &rc); + if (rc) { + sResult = s; + } else { + sResult = pszDemangled; + } + if (pszDemangled) { + free(pszDemangled); + } +#endif + return sResult; +} + +TypeMap ObjectCounter::getObjectCount(){ + return m_TypeMap; +} + +} diff --git a/src/base/ObjectCounter.h b/src/base/ObjectCounter.h new file mode 100644 index 0000000..e370723 --- /dev/null +++ b/src/base/ObjectCounter.h @@ -0,0 +1,61 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _ObjectCounter_H_ +#define _ObjectCounter_H_ + +#include "../api.h" +#include <string> +#include <map> +#include <typeinfo> + +namespace avg { + +typedef std::map<const std::type_info *, int> TypeMap; + +class AVG_API ObjectCounter { +public: + static ObjectCounter* get(); + virtual ~ObjectCounter(); + + void incRef(const std::type_info* pType); + void decRef(const std::type_info* pType); + + int getCount(const std::type_info* pType); + + std::string demangle(std::string s); + std::string dump(); + TypeMap getObjectCount(); + +private: + ObjectCounter(); + static void deleteSingleton(); + + TypeMap m_TypeMap; + + static ObjectCounter* s_pObjectCounter; + static bool s_bDeleted; + friend void deleteObjectCounter(); +}; + +} +#endif + diff --git a/src/base/ProfilingZone.cpp b/src/base/ProfilingZone.cpp new file mode 100644 index 0000000..9cdbbfe --- /dev/null +++ b/src/base/ProfilingZone.cpp @@ -0,0 +1,91 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "ProfilingZone.h" +#include "ObjectCounter.h" + +#include <iostream> + +using namespace boost; +using namespace std; + +namespace avg { + +ProfilingZone::ProfilingZone(const ProfilingZoneID& zoneID) + : m_TimeSum(0), + m_AvgTime(0), + m_NumFrames(0), + m_Indent(0), + m_ZoneID(zoneID) +{ + ObjectCounter::get()->incRef(&typeid(*this)); +} + +ProfilingZone::~ProfilingZone() +{ + ObjectCounter::get()->decRef(&typeid(*this)); +} + +void ProfilingZone::restart() +{ + m_NumFrames = 0; + m_AvgTime = 0; + m_TimeSum = 0; +} + +void ProfilingZone::reset() +{ + m_NumFrames++; + m_AvgTime = (m_AvgTime*(m_NumFrames-1)+m_TimeSum)/m_NumFrames; + m_TimeSum = 0; +} + +long long ProfilingZone::getUSecs() const +{ + return m_TimeSum; +} + +long long ProfilingZone::getAvgUSecs() const +{ + return m_AvgTime; +} + +void ProfilingZone::setIndentLevel(int indent) +{ + m_Indent = indent; +} + +int ProfilingZone::getIndentLevel() const +{ + return m_Indent; +} + +string ProfilingZone::getIndentString() const +{ + return string(m_Indent, ' '); +} + +const string& ProfilingZone::getName() const +{ + return m_ZoneID.getName(); +} + +} diff --git a/src/base/ProfilingZone.h b/src/base/ProfilingZone.h new file mode 100644 index 0000000..0d0ee42 --- /dev/null +++ b/src/base/ProfilingZone.h @@ -0,0 +1,69 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _ProfilingZone_H_ +#define _ProfilingZone_H_ + +#include "../api.h" +#include "ProfilingZoneID.h" +#include "TimeSource.h" + +#include <boost/shared_ptr.hpp> + +namespace avg { + +class AVG_API ProfilingZone +{ +public: + ProfilingZone(const ProfilingZoneID& zoneID); + virtual ~ProfilingZone(); + void restart(); + + void start() + { + m_StartTime = TimeSource::get()->getCurrentMicrosecs(); + }; + void stop() + { + m_TimeSum += TimeSource::get()->getCurrentMicrosecs()-m_StartTime; + }; + void reset(); + long long getUSecs() const; + long long getAvgUSecs() const; + void setIndentLevel(int indent); + int getIndentLevel() const; + std::string getIndentString() const; + const std::string& getName() const; + +private: + long long m_TimeSum; + long long m_AvgTime; + long long m_StartTime; + int m_NumFrames; + int m_Indent; + const ProfilingZoneID& m_ZoneID; +}; + +typedef boost::shared_ptr<ProfilingZone> ProfilingZonePtr; + +} + +#endif diff --git a/src/base/ProfilingZoneID.cpp b/src/base/ProfilingZoneID.cpp new file mode 100644 index 0000000..7256887 --- /dev/null +++ b/src/base/ProfilingZoneID.cpp @@ -0,0 +1,57 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "ProfilingZoneID.h" +#include "ThreadProfiler.h" + +using namespace std; + +namespace avg { + +ProfilingZoneID::ProfilingZoneID(const string& sName, bool bMultithreaded) + : m_sName(sName), + m_bMultithreaded(bMultithreaded), + m_pProfiler(0) +{ +} + +ProfilingZoneID::~ProfilingZoneID() +{ +} + +const string& ProfilingZoneID::getName() const +{ + return m_sName; +} + +ThreadProfiler* ProfilingZoneID::getProfiler() +{ + if (!m_pProfiler) { + if (m_bMultithreaded) { + return ThreadProfiler::get(); + } else { + m_pProfiler = ThreadProfiler::get(); + } + } + return m_pProfiler; +} + +} diff --git a/src/base/ProfilingZoneID.h b/src/base/ProfilingZoneID.h new file mode 100644 index 0000000..ca4d637 --- /dev/null +++ b/src/base/ProfilingZoneID.h @@ -0,0 +1,50 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _ProfilingZoneID_H_ +#define _ProfilingZoneID_H_ + +#include "../api.h" + +#include <string> + +namespace avg { + +class ThreadProfiler; + +class AVG_API ProfilingZoneID +{ +public: + ProfilingZoneID(const std::string& sName, bool bMultithreaded=false); + ~ProfilingZoneID(); + + const std::string& getName() const; + ThreadProfiler* getProfiler(); + +private: + std::string m_sName; + bool m_bMultithreaded; + ThreadProfiler* m_pProfiler; +}; + +} + +#endif diff --git a/src/base/Queue.h b/src/base/Queue.h new file mode 100644 index 0000000..36a0eba --- /dev/null +++ b/src/base/Queue.h @@ -0,0 +1,160 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Queue_H_ +#define _Queue_H_ + +#include "../api.h" +#include "Exception.h" + +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition.hpp> +#include <boost/shared_ptr.hpp> + +#include <deque> +#include <iostream> + +namespace avg { + +typedef boost::unique_lock<boost::mutex> unique_lock; + +template<class QElement> +class AVG_TEMPLATE_API Queue +{ +public: + typedef boost::shared_ptr<QElement> QElementPtr; + + Queue(int maxSize=-1); + virtual ~Queue(); + + bool empty() const; + QElementPtr pop(bool bBlock = true); + void clear(); + void push(const QElementPtr& pElem); + QElementPtr peek(bool bBlock = true) const; + int size() const; + int getMaxSize() const; + +private: + QElementPtr getFrontElement(bool bBlock, unique_lock& Lock) const; + + std::deque<QElementPtr> m_pElements; + mutable boost::mutex m_Mutex; + mutable boost::condition m_Cond; + int m_MaxSize; +}; + +template<class QElement> +Queue<QElement>::Queue(int maxSize) + : m_MaxSize(maxSize) +{ +} + +template<class QElement> +Queue<QElement>::~Queue() +{ +} + +template<class QElement> +bool Queue<QElement>::empty() const +{ + unique_lock Lock(m_Mutex); + return m_pElements.empty(); +} + +template<class QElement> +typename Queue<QElement>::QElementPtr Queue<QElement>::pop(bool bBlock) +{ + unique_lock lock(m_Mutex); + QElementPtr pElem = getFrontElement(bBlock, lock); + if (pElem) { + m_pElements.pop_front(); + m_Cond.notify_one(); + } + return pElem; +} + +template<class QElement> +void Queue<QElement>::clear() +{ + QElementPtr pElem; + do { + pElem = pop(false); + } while (pElem); +} + +template<class QElement> +typename Queue<QElement>::QElementPtr Queue<QElement>::peek(bool bBlock) const +{ + unique_lock lock(m_Mutex); + QElementPtr pElem = getFrontElement(bBlock, lock); + if (pElem) { + m_Cond.notify_one(); + } + return pElem; +} + +template<class QElement> +void Queue<QElement>::push(const QElementPtr& pElem) +{ + assert(pElem); + unique_lock lock(m_Mutex); + if (m_pElements.size() == (unsigned)m_MaxSize) { + while (m_pElements.size() == (unsigned)m_MaxSize) { + m_Cond.wait(lock); + } + } + m_pElements.push_back(pElem); + m_Cond.notify_one(); +} + +template<class QElement> +int Queue<QElement>::size() const +{ + unique_lock lock(m_Mutex); + return int(m_pElements.size()); +} + +template<class QElement> +int Queue<QElement>::getMaxSize() const +{ + unique_lock lock(m_Mutex); + return m_MaxSize; +} + +template<class QElement> +typename Queue<QElement>::QElementPtr + Queue<QElement>::getFrontElement(bool bBlock, unique_lock& lock) const +{ + if (m_pElements.empty()) { + if (bBlock) { + while (m_pElements.empty()) { + m_Cond.wait(lock); + } + } else { + return QElementPtr(); + } + } + return m_pElements.front(); +} + +} +#endif diff --git a/src/base/Rect.h b/src/base/Rect.h new file mode 100644 index 0000000..d668338 --- /dev/null +++ b/src/base/Rect.h @@ -0,0 +1,213 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Rect_H_ +#define _Rect_H_ + +#include "../api.h" + +#include "../base/GLMHelper.h" +#include "../glm/glm.hpp" + +#include <algorithm> + +namespace avg { + +// Simple rectangle class. +// If NUM is an integer, contains all points from tl up to but not including +// br. +template<class NUM> +class AVG_TEMPLATE_API Rect +{ +public: + typedef glm::detail::tvec2<NUM> Vec2; + Vec2 tl; + Vec2 br; + + Rect(); + Rect(NUM left, NUM top, NUM right, NUM bottom); + Rect(const Vec2& TL, const Vec2& BR); + template<class ORIGNUM> Rect(const Rect<ORIGNUM>& rc); + + bool operator ==(const Rect<NUM>& rect) const; + bool operator !=(const Rect<NUM> & rect) const; + NUM width() const; + NUM height() const; + Vec2 center() const; + void setWidth(NUM width); + void setHeight(NUM height); + void setSize(const Vec2& size); + bool contains(const Vec2& pt) const; + bool contains(const Rect<NUM>& rect) const; + bool intersects(const Rect<NUM>& rect) const; + void expand(const Rect<NUM>& rect); + void intersect(const Rect<NUM>& rect); + Vec2 size() const; + Vec2 cropPoint(const Vec2& pt) const; +}; + +template<class NUM> +std::ostream& operator<<( std::ostream& os, const Rect<NUM> &r) +{ + os << "(" << r.tl << "-" << r.br << ")"; + return os; +} + + +typedef Rect<float> FRect; +typedef Rect<int> IntRect; + +template<class NUM> +Rect<NUM>::Rect() +{} + +template<class NUM> +Rect<NUM>::Rect(const Vec2& TL, const Vec2& BR) + : tl(TL), br(BR) +{} + +template<class NUM> +Rect<NUM>::Rect(NUM left, NUM top, NUM right, NUM bottom) + : tl(left, top), + br(right, bottom) +{} + +template<class NUM> +template<class ORIGNUM> +Rect<NUM>::Rect(const Rect<ORIGNUM>& rc) + : tl (NUM(rc.tl.x), NUM(rc.tl.y)), + br (NUM(rc.br.x), NUM(rc.br.y)) +{ +} + +template<class NUM> +bool Rect<NUM>::operator ==(const Rect<NUM> & rect) const +{ + return (tl == rect.tl && br == rect.br); +} + +template<class NUM> +bool Rect<NUM>::operator !=(const Rect<NUM> & rect) const +{ + return !(rect==*this); +} + +template<class NUM> +NUM Rect<NUM>::width() const +{ + return br.x-tl.x; +} + +template<class NUM> +NUM Rect<NUM>::height() const +{ + return br.y-tl.y; +} + +template<class NUM> +glm::detail::tvec2<NUM> Rect<NUM>::center() const +{ + return Vec2(tl+br)/2; +} + +template<class NUM> +void Rect<NUM>::setWidth(NUM width) +{ + br.x = tl.x+width; +} + +template<class NUM> +void Rect<NUM>::setHeight(NUM height) +{ + br.y = tl.y+height; +} + +template<class NUM> +void Rect<NUM>::setSize(const Vec2& size) +{ + setWidth(size.x); + setHeight(size.y); +} + +template<class NUM> +bool Rect<NUM>::contains(const Vec2& pt) const +{ + return (pt.x >= tl.x && pt.x < br.x && + pt.y >= tl.y && pt.y < br.y); +} + +template<class NUM> +bool Rect<NUM>::contains(const Rect<NUM>& rect) const +{ + Vec2 brpt (rect.br.x-1, rect.br.y-1); + return Contains(rect.tl) && Contains(brpt); +} + +template<class NUM> +bool Rect<NUM>::intersects(const Rect<NUM>& rect) const +{ + if (rect.br.x <= tl.x || rect.tl.x >= br.x || + rect.br.y <= tl.y || rect.tl.y >= br.y) + return false; + else + return true; +} + +template<class NUM> +void Rect<NUM>::expand(const Rect<NUM>& rect) +{ + tl.x = glm::min(tl.x, rect.tl.x); + tl.y = glm::min(tl.y, rect.tl.y); + br.x = glm::max(br.x, rect.br.x); + br.y = glm::max(br.y, rect.br.y); +} + +template<class NUM> +void Rect<NUM>::intersect(const Rect<NUM>& rect) +{ + tl.x = glm::max(tl.x, rect.tl.x); + tl.y = glm::max(tl.y, rect.tl.y); + br.x = glm::min(br.x, rect.br.x); + br.y = glm::min(br.y, rect.br.y); +} + +template<class NUM> +glm::detail::tvec2<NUM> Rect<NUM>::size() const +{ + return Vec2(width(), height()); +} + +template<class NUM> +glm::detail::tvec2<NUM> Rect<NUM>::cropPoint(const Vec2& pt) const +{ + Vec2 Result; + Result.x = std::min(std::max(pt.x, tl.x), br.x-1); + Result.y = std::min(std::max(pt.y, tl.y), br.y-1); + return Result; +} + +#undef min +#undef max + +} + +#endif + diff --git a/src/base/ScopeTimer.cpp b/src/base/ScopeTimer.cpp new file mode 100644 index 0000000..eb95736 --- /dev/null +++ b/src/base/ScopeTimer.cpp @@ -0,0 +1,35 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "ScopeTimer.h" + +using namespace std; + +namespace avg { + +bool ScopeTimer::s_bTimersEnabled = false; + +void ScopeTimer::enableTimers(bool bEnable) +{ + s_bTimersEnabled = bEnable; +} + +} diff --git a/src/base/ScopeTimer.h b/src/base/ScopeTimer.h new file mode 100644 index 0000000..a87263f --- /dev/null +++ b/src/base/ScopeTimer.h @@ -0,0 +1,60 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _ScopeTimer_H_ +#define _ScopeTimer_H_ + +#include "../api.h" +#include "ProfilingZoneID.h" +#include "ThreadProfiler.h" + +namespace avg { + +class AVG_API ScopeTimer { +public: + ScopeTimer(ProfilingZoneID& zoneID) + { + if (s_bTimersEnabled) { + m_pZoneID = &zoneID; + m_pZoneID->getProfiler()->startZone(zoneID); + } else { + m_pZoneID = 0; + } + }; + + ~ScopeTimer() + { + if (m_pZoneID) { + m_pZoneID->getProfiler()->stopZone(*m_pZoneID); + } + }; + + static void enableTimers(bool bEnable); + +private: + ProfilingZoneID* m_pZoneID; + + static bool s_bTimersEnabled; +}; + +} + +#endif diff --git a/src/base/Signal.h b/src/base/Signal.h new file mode 100644 index 0000000..b670822 --- /dev/null +++ b/src/base/Signal.h @@ -0,0 +1,119 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Signal_H_ +#define _Signal_H_ + +#include "../api.h" + +#include "Exception.h" + +#include <list> + +namespace avg { + + +// Simple implementation of a signal/slot mechanism. +// Might need to be replaced by boost::signal when things get more complicated. +template <class LISTENEROBJ> +class AVG_TEMPLATE_API Signal { +public: + typedef void (LISTENEROBJ::*ListenerFunc)() ; + Signal(ListenerFunc pFunc); + virtual ~Signal(); + + void connect(LISTENEROBJ* pListener); + void disconnect(LISTENEROBJ* pListener); + + void emit(); + int getNumListeners() const; + +private: + ListenerFunc m_pFunc; + std::list<LISTENEROBJ*> m_Listeners; + typedef typename std::list<LISTENEROBJ*>::iterator ListenerIterator; + LISTENEROBJ* m_pCurrentListener; + bool m_bKillCurrentListener; +}; + +template<class LISTENEROBJ> +Signal<LISTENEROBJ>::Signal(ListenerFunc pFunc) + : m_pFunc(pFunc), + m_pCurrentListener(0), + m_bKillCurrentListener(false) +{ +} + +template<class LISTENEROBJ> +Signal<LISTENEROBJ>::~Signal() +{ +} + +template<class LISTENEROBJ> +void Signal<LISTENEROBJ>::connect(LISTENEROBJ* pListener) +{ + ListenerIterator it; + it = find(m_Listeners.begin(), m_Listeners.end(), pListener); + // If the listener is already connected, something is wrong, unless we're + // deleting it at this very moment. + AVG_ASSERT(it == m_Listeners.end() || + (*it == m_pCurrentListener && m_bKillCurrentListener)); + m_Listeners.push_back(pListener); +} + +template<class LISTENEROBJ> +void Signal<LISTENEROBJ>::disconnect(LISTENEROBJ* pListener) +{ + if (m_pCurrentListener == pListener) { + m_bKillCurrentListener = true; + } else { + ListenerIterator it; + it = find(m_Listeners.begin(), m_Listeners.end(), pListener); + AVG_ASSERT(it != m_Listeners.end()); + m_Listeners.erase(it); + } +} + +template<class LISTENEROBJ> +void Signal<LISTENEROBJ>::emit() +{ + ListenerIterator it; + for (it=m_Listeners.begin(); it != m_Listeners.end();) { + m_pCurrentListener = *it; + ((*it)->*m_pFunc)(); // This is the actual call to the listener. + if (m_bKillCurrentListener) { + it = m_Listeners.erase(it); + m_bKillCurrentListener = false; + } else { + ++it; + } + } + m_pCurrentListener = 0; +} + +template<class LISTENEROBJ> +int Signal<LISTENEROBJ>::getNumListeners() const +{ + return m_Listeners.size(); +} + +} +#endif diff --git a/src/base/StandardLogSink.cpp b/src/base/StandardLogSink.cpp new file mode 100644 index 0000000..510aa0b --- /dev/null +++ b/src/base/StandardLogSink.cpp @@ -0,0 +1,54 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de + +#include "StandardLogSink.h" +#include "Logger.h" + +#include <iostream> +#include <iomanip> + +using namespace std; + +namespace avg +{ + +StandardLogSink::StandardLogSink() +{ + +} + +StandardLogSink::~StandardLogSink() +{ + +} + +void StandardLogSink::logMessage(const tm* pTime, unsigned millis, + const category_t& category, severity_t severity, const UTF8String& sMsg) +{ + char timeString[256]; + strftime(timeString, sizeof(timeString), "%y-%m-%d %H:%M:%S", pTime); + cerr << "[" << timeString << "." << + setw(3) << setfill('0') << millis << setw(0) << "]["; + cerr << setw(4) << setfill('.') << Logger::severityToString(severity) << "]["; + cerr << setw(9) << setfill('.') << category << "] : " << sMsg << endl; + cerr.flush(); +} + +} diff --git a/src/base/StandardLogSink.h b/src/base/StandardLogSink.h new file mode 100644 index 0000000..7cbfe2c --- /dev/null +++ b/src/base/StandardLogSink.h @@ -0,0 +1,39 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de + +#ifndef _StandardLogSink_H_ +#define _StandardLogSink_H_ + +#include "ILogSink.h" + +namespace avg{ + +class StandardLogSink: public ILogSink +{ +public: + StandardLogSink(); + virtual ~StandardLogSink (); + + virtual void logMessage(const tm* pTime, unsigned millis, const category_t& category, + severity_t severity, const UTF8String& sMsg); +}; + +} +#endif diff --git a/src/base/StringHelper.cpp b/src/base/StringHelper.cpp new file mode 100644 index 0000000..6155859 --- /dev/null +++ b/src/base/StringHelper.cpp @@ -0,0 +1,145 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "StringHelper.h" + +#include <stdlib.h> +#include <ctype.h> +#include <algorithm> +#include <cstdio> +#include <iterator> + +using namespace std; + +namespace avg { + +bool isWhitespace(const string& s) +{ + return s.find_first_not_of(" \n\r\t") == s.npos; +} + +void skipWhitespace(std::istream& is) +{ + string sWhitespace(" \n\r\t"); + bool bWhitespace; + do { + int i = is.peek(); + if (i == EOF) { + bWhitespace = false; + } else { + bWhitespace = (sWhitespace.find(char(i)) != sWhitespace.npos); + } + if (bWhitespace) { + is.ignore(); + } + } while (bWhitespace); +} + +void skipToken(std::istream& is, char token) +{ + skipWhitespace(is); + int i = is.peek(); + if (i == token) { + is.ignore(); + } else { + is.setstate(ios::failbit); + } +} + +int stringToInt(const string& s) +{ + int i; + fromString(s, i); + return i; +} + +float stringToFloat(const string& s) +{ + float d; + fromString(s, d); + return d; +} + +bool stringToBool(const string& s) +{ + // avg usually wants xml attributes in lowercase, but python only + // sees 'True' as true, so we'll accept that too. Also, python 2.3 + // has 1 as true, so that has to be ok too. + if (s == "True" || s == "true" || s == "1") { + return true; + } + if (s == "False" || s == "false" || s == "0") { + return false; + } + throw (Exception(AVG_ERR_TYPE, string("Could not convert ")+s+" to bool.")); +} + +std::string removeStartEndSpaces(const string& s) +{ + string sResult = s; + while (sResult.size() > 0 && (sResult[0] == ' ' || sResult[0] == '\n' + || sResult[0] == '\r' || sResult[0] == '\t')) + { + sResult.erase(0, 1); + } + if (sResult.size() == 0) { + return sResult; + } + char c = sResult[sResult.length()-1]; + while (c == ' ' || c == '\n' || c == '\r' || c == '\t') { + sResult.erase(sResult.length()-1, 1); + c = sResult[sResult.length()-1]; + } + return sResult; +} + +string toLowerCase(const string& s) +{ + string sResult; + for (unsigned i=0; i<s.length(); ++i) { + sResult.push_back(::tolower(s[i])); + } + return sResult; +} + +bool equalIgnoreCase(const string& s1, const string& s2) +{ + if (s1.length() != s2.length()) { + return false; + } + string sUpper1; + string sUpper2; + transform(s1.begin(), s1.end(), std::back_inserter(sUpper1), (int(*)(int)) toupper); + transform(s2.begin(), s2.end(), std::back_inserter(sUpper2), (int(*)(int)) toupper); + return sUpper1 == sUpper2; +} + +string toString(const bool& b) +{ + if (b) { + return "true"; + } else { + return "false"; + } +} + +} + diff --git a/src/base/StringHelper.h b/src/base/StringHelper.h new file mode 100644 index 0000000..82713eb --- /dev/null +++ b/src/base/StringHelper.h @@ -0,0 +1,133 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _StringHelper_H_ +#define _StringHelper_H_ + +#include "../api.h" +#include "Exception.h" + +#include <string> +#include <sstream> +#include <typeinfo> +#include <iostream> +#include <vector> + +#ifdef __GNUC__ +#include <cxxabi.h> +#endif + +namespace avg { + +bool AVG_API isWhitespace(const std::string& s); +void AVG_API skipWhitespace(std::istream& is); +void AVG_API skipToken(std::istream& is, char token); + +template<class T> +std::istream& operator >>(std::istream& is, std::vector<T>& v) +{ + skipToken(is, '('); + skipWhitespace(is); + int c = is.peek(); + if (c == ')') { + is.ignore(); + return is; + } + bool bDone = false; + do { + T elem; + is >> elem; + v.push_back(elem); + skipWhitespace(is); + int c = is.peek(); + switch(c) { + case ',': + is.ignore(); + break; + case ')': + bDone = true; + is.ignore(); + break; + default: + is.setstate(std::ios::failbit); + bDone = true; + } + } while (!bDone); + return is; +} + +int AVG_API stringToInt(const std::string& s); +float AVG_API stringToFloat(const std::string& s); +bool AVG_API stringToBool(const std::string& s); + +std::string AVG_API removeStartEndSpaces(const std::string& s); + +std::string AVG_API toLowerCase(const std::string& s); + +bool AVG_API equalIgnoreCase(const std::string& s1, const std::string& s2); + +template<class T> +std::string toString(const T& i) +{ + std::stringstream stream; + stream << i; + return stream.str(); +} + +std::string AVG_API toString(const bool& b); + +template<class T> +std::string getFriendlyTypeName(const T& dummy) +{ + std::string sTypeName = typeid(T).name(); +#ifdef __GNUC__ + int status; + char* const pClearName = abi::__cxa_demangle (sTypeName.c_str(), 0, 0, &status); + if (status == 0) { + sTypeName = pClearName; + } +#endif + return sTypeName; +} + +template<class T> +void fromString(const std::string& s, T& result) +{ + std::stringstream stream(s); + bool bOk = (stream >> result) != 0; + if (bOk) { + std::string sLeftover; + stream >> sLeftover; + bOk = isWhitespace(sLeftover); + } + if (!bOk) { + std::string sTypeName = getFriendlyTypeName(result); + throw (Exception(AVG_ERR_TYPE, std::string("Could not convert '")+s + + "' to "+sTypeName+".")); + } +} + + +} + + + +#endif diff --git a/src/base/Test.cpp b/src/base/Test.cpp new file mode 100644 index 0000000..b2c0b12 --- /dev/null +++ b/src/base/Test.cpp @@ -0,0 +1,114 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "Test.h" + +#include "../base/OSHelper.h" + +#include <iostream> +#include <stdlib.h> + +using namespace std; + +namespace avg { + +string Test::s_sSrcDirName; + +Test::Test(const string & sName, int indentLevel) + : m_IndentLevel(indentLevel), + m_NumSucceeded(0), + m_NumFailed(0), + m_sName(sName) +{ +} + +Test::~Test() +{ +} + +void Test::test(bool b, const char * pszFile, int line) +{ + if (b) { + m_NumSucceeded++; + } else { + cerr << string(m_IndentLevel, ' ') << " ---->> failed at " << pszFile + << ", " << line << endl; + m_NumFailed++; + } +} + + +bool Test::isOk() +{ + return m_NumFailed == 0; +} + +void Test::setFailed() +{ + m_NumFailed++; +} + +int Test::getNumSucceeded() const +{ + return m_NumSucceeded; +} + +int Test::getNumFailed() const +{ + return m_NumFailed; +} + +const std::string& Test::getName() const +{ + return m_sName; +} + +void Test::aggregateStatistics(const Test& ChildTest) +{ + m_NumSucceeded += ChildTest.getNumSucceeded(); + m_NumFailed += ChildTest.getNumFailed(); +} + +void Test::printResults() +{ + if (m_NumFailed == 0) { + cerr << string(m_IndentLevel, ' ') << m_sName << " succeeded." << endl; + } else { + cerr << string(m_IndentLevel, ' ') << "######## " << m_sName << + " failed. ########" << endl; + } + +} + +const string& Test::getSrcDirName() +{ + if (s_sSrcDirName == "") { + bool bInEnviron = getEnv("srcdir", s_sSrcDirName); + if (!bInEnviron) { + s_sSrcDirName = "."; + } + s_sSrcDirName += "/"; + } + return s_sSrcDirName; +} + +} + diff --git a/src/base/Test.h b/src/base/Test.h new file mode 100644 index 0000000..0cc20ba --- /dev/null +++ b/src/base/Test.h @@ -0,0 +1,81 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Test_H_ +#define _Test_H_ + +#include "../api.h" +#include <boost/shared_ptr.hpp> + +#include <iostream> +#include <sstream> +#include <string> + +namespace avg { +class AVG_API Test +{ +public: + Test(const std::string & sName, int indentLevel); + virtual ~Test(); + + bool isOk(); + virtual void runTests() = 0; + + void test(bool b, const char * pszFile, int line); + void setFailed(); + + int getNumSucceeded() const; + int getNumFailed() const; + const std::string& getName() const; + + void aggregateStatistics(const Test& childTest); + virtual void printResults(); + +protected: + static const std::string& getSrcDirName(); + static std::string s_sSrcDirName; + + int m_IndentLevel; + +private: + int m_NumSucceeded; + int m_NumFailed; + std::string m_sName; +}; + +typedef boost::shared_ptr<Test> TestPtr; + +#define TEST_FAILED(s) \ + cerr << string(m_IndentLevel+6, ' ') << s << endl; \ + test(false, __FILE__, __LINE__); + +#define TEST(b) \ + cerr << string(m_IndentLevel+4, ' ') << " TEST(" << #b << ")" << endl; \ + test(b, __FILE__, __LINE__); + +#define QUIET_TEST(b) \ + if(!(b)) { \ + cerr << string(m_IndentLevel+4, ' ') << " TEST(" << #b << ")" << endl; \ + } \ + test(b, __FILE__, __LINE__); +} +#endif + diff --git a/src/base/TestSuite.cpp b/src/base/TestSuite.cpp new file mode 100644 index 0000000..16a254c --- /dev/null +++ b/src/base/TestSuite.cpp @@ -0,0 +1,72 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "TestSuite.h" +#include "Exception.h" + +using namespace std; + +namespace avg { + +TestSuite::TestSuite(const string& sName) + : Test(sName, 0) +{ +} + +TestSuite::~TestSuite() +{ +} + +void TestSuite::addTest(TestPtr pNewTest) +{ + m_Tests.push_back(pNewTest); +} + +void TestSuite::runTests() +{ + cerr << string(m_IndentLevel, ' ') << "Running suite " << getName() << endl; + for (unsigned i = 0; i < m_Tests.size(); ++i) { + cerr << string(m_IndentLevel, ' ') << " Running " + << m_Tests[i]->getName() << endl; + try { + m_Tests[i]->runTests(); + aggregateStatistics(*m_Tests[i]); + m_Tests[i]->printResults(); + } catch (Exception& ex) { + cerr << string(m_IndentLevel, ' ') << ex.getStr() << endl; + setFailed(); + } catch (std::exception& ex) { + cerr << string(m_IndentLevel, ' ') << " ---->> failed, std::exception: " + << ex.what() << endl; + setFailed(); + } catch (...) { + cerr << string(m_IndentLevel, ' ') << + " ---->> failed, exception caught" << endl; + setFailed(); + } + } + + printResults(); +} + + +} + diff --git a/src/base/TestSuite.h b/src/base/TestSuite.h new file mode 100644 index 0000000..124bbc2 --- /dev/null +++ b/src/base/TestSuite.h @@ -0,0 +1,49 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _TestSuite_H_ +#define _TestSuite_H_ + +#include "../api.h" +#include "Test.h" + +#include <iostream> +#include <sstream> +#include <vector> + +namespace avg { +class AVG_API TestSuite: public Test +{ +public: + TestSuite(const std::string& sName); + virtual ~TestSuite(); + + void addTest(TestPtr pNewTest); + + virtual void runTests(); + +private: + std::vector<TestPtr> m_Tests; +}; + +} +#endif + diff --git a/src/base/ThreadHelper.cpp b/src/base/ThreadHelper.cpp new file mode 100644 index 0000000..105e116 --- /dev/null +++ b/src/base/ThreadHelper.cpp @@ -0,0 +1,94 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "ThreadHelper.h" +#include "OSHelper.h" + +#ifdef _WIN32 +#include <Windows.h> +#endif + +namespace avg { + +void setAffinityMask(bool bIsMainThread) +{ + // The main thread gets the first processor to itself. All other threads share the + // rest of the processors available, unless, of course, there is only one processor + // in the machine. +#ifdef linux + static cpu_set_t allProcessors; + static bool bInitialized = false; + if (!bInitialized) { + int rc = sched_getaffinity(0, sizeof(allProcessors), &allProcessors); + AVG_ASSERT(rc == 0); +// cerr << "All processors: "; +// printAffinityMask(allProcessors); + bInitialized = true; + } + cpu_set_t mask; + if (bIsMainThread) { + CPU_ZERO(&mask); + CPU_SET(0, &mask); +// cerr << "Main Thread: "; + } else { + mask = allProcessors; + if (CPU_COUNT(&mask) > 1) { + CPU_CLR(0, &mask); + } +// cerr << "Aux Thread: "; + } +// printAffinityMask(mask); + int rc = sched_setaffinity(0, sizeof(mask), &mask); + AVG_ASSERT(rc == 0); +#elif defined _WIN32 + DWORD processAffinityMask; + DWORD systemAffinityMask; + BOOL rc = GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, + &systemAffinityMask); + AVG_ASSERT(rc == TRUE); + DWORD mainThreadMask = 1 << getLowestBitSet(processAffinityMask); + DWORD mask; + if (bIsMainThread) { + mask = mainThreadMask; + } else { + mask = processAffinityMask & ~mainThreadMask; + if (mask == 0) { + mask = processAffinityMask; + } + } + DWORD_PTR pPrevMask = SetThreadAffinityMask(GetCurrentThread(), mask); + AVG_ASSERT_MSG(pPrevMask != 0, getWinErrMsg(GetLastError()).c_str()); +#endif +} + +unsigned getLowestBitSet(unsigned val) +{ + AVG_ASSERT(val != 0); // Doh + + unsigned pos = 0; + while (!(val & 1)) { + val >>= 1; + ++pos; + } + return pos; +} + +} diff --git a/src/base/ThreadHelper.h b/src/base/ThreadHelper.h new file mode 100644 index 0000000..7acf640 --- /dev/null +++ b/src/base/ThreadHelper.h @@ -0,0 +1,37 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _ThreadHelper_H_ +#define _ThreadHelper_H_ + +#include "Exception.h" +#include <boost/thread.hpp> +#include <boost/thread/locks.hpp> + +namespace avg { + +void AVG_API setAffinityMask(bool bIsMainThread); +typedef boost::lock_guard<boost::mutex> lock_guard; +unsigned getLowestBitSet(unsigned val); + +} + +#endif diff --git a/src/base/ThreadProfiler.cpp b/src/base/ThreadProfiler.cpp new file mode 100644 index 0000000..1f1a354 --- /dev/null +++ b/src/base/ThreadProfiler.cpp @@ -0,0 +1,184 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "ThreadProfiler.h" + +#include "Logger.h" +#include "Exception.h" +#include "ProfilingZone.h" +#include "ScopeTimer.h" + +#include <sstream> +#include <iomanip> +#include <iostream> + +using namespace std; +using namespace boost; + +namespace avg { + +thread_specific_ptr<ThreadProfiler*> ThreadProfiler::s_pInstance; + +ThreadProfiler* ThreadProfiler::get() +{ + if (s_pInstance.get() == 0) { + s_pInstance.reset(new (ThreadProfiler*)); + *s_pInstance = new ThreadProfiler(); + } + return *s_pInstance; +} + +void ThreadProfiler::kill() +{ + delete *s_pInstance; + s_pInstance.reset(); +} + +ThreadProfiler::ThreadProfiler() + : m_sName(""), + m_LogCategory(Logger::category::PROFILE) +{ + m_bRunning = false; + ScopeTimer::enableTimers(Logger::get()->shouldLog(m_LogCategory, + Logger::severity::INFO)); +} + +ThreadProfiler::~ThreadProfiler() +{ +} + +void ThreadProfiler::setLogCategory(category_t category) +{ + AVG_ASSERT(!m_bRunning); + m_LogCategory = category; +} + +void ThreadProfiler::start() +{ + m_bRunning = true; +} + +void ThreadProfiler::restart() +{ + ZoneVector::iterator it; + for (it = m_Zones.begin(); it != m_Zones.end(); ++it) { + (*it)->restart(); + } +} + +void ThreadProfiler::startZone(const ProfilingZoneID& zoneID) +{ + ZoneMap::iterator it = m_ZoneMap.find(&zoneID); + // Duplicated code to avoid instantiating a new smart pointer when it's not + // necessary. + if (it == m_ZoneMap.end()) { + ProfilingZonePtr pZone = addZone(zoneID); + pZone->start(); + m_ActiveZones.push_back(pZone); + } else { + ProfilingZonePtr& pZone = it->second; + pZone->start(); + m_ActiveZones.push_back(pZone); + } +} + +void ThreadProfiler::stopZone(const ProfilingZoneID& zoneID) +{ + ZoneMap::iterator it = m_ZoneMap.find(&zoneID); + ProfilingZonePtr& pZone = it->second; + pZone->stop(); + m_ActiveZones.pop_back(); +} + +void ThreadProfiler::dumpStatistics() +{ + if (!m_Zones.empty()) { + AVG_TRACE(m_LogCategory, Logger::severity::INFO, "Thread " << m_sName); + AVG_TRACE(m_LogCategory, Logger::severity::INFO, + "Zone name Avg. time"); + AVG_TRACE(m_LogCategory, Logger::severity::INFO, + "--------- ---------"); + + ZoneVector::iterator it; + for (it = m_Zones.begin(); it != m_Zones.end(); ++it) { + AVG_TRACE(m_LogCategory, Logger::severity::INFO, + std::setw(35) << std::left + << ((*it)->getIndentString()+(*it)->getName()) + << std::setw(9) << std::right << (*it)->getAvgUSecs()); + } + AVG_TRACE(m_LogCategory, Logger::severity::INFO, ""); + } +} + +void ThreadProfiler::reset() +{ + ZoneVector::iterator it; + for (it = m_Zones.begin(); it != m_Zones.end(); ++it) { + (*it)->reset(); + } +} + +int ThreadProfiler::getNumZones() +{ + return m_Zones.size(); +} + +const std::string& ThreadProfiler::getName() const +{ + return m_sName; +} + +void ThreadProfiler::setName(const std::string& sName) +{ + m_sName = sName; +} + + +ProfilingZonePtr ThreadProfiler::addZone(const ProfilingZoneID& zoneID) +{ + ProfilingZonePtr pZone(new ProfilingZone(zoneID)); + m_ZoneMap[&zoneID] = pZone; + ZoneVector::iterator it; + int parentIndent = -2; + if (m_ActiveZones.empty()) { + it = m_Zones.end(); + } else { + ProfilingZonePtr pActiveZone = m_ActiveZones.back(); + bool bParentFound = false; + for (it = m_Zones.begin(); it != m_Zones.end(); ++it) + { + if (pActiveZone == *it) { + bParentFound = true; + break; + } + } + AVG_ASSERT(bParentFound); + parentIndent = pActiveZone->getIndentLevel(); + ++it; + for (; it != m_Zones.end() && (*it)->getIndentLevel() > parentIndent; ++it) {}; + } + m_Zones.insert(it, pZone); + pZone->setIndentLevel(parentIndent+2); + return pZone; +} + +} + diff --git a/src/base/ThreadProfiler.h b/src/base/ThreadProfiler.h new file mode 100644 index 0000000..a581271 --- /dev/null +++ b/src/base/ThreadProfiler.h @@ -0,0 +1,88 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _ThreadProfiler_H_ +#define _ThreadProfiler_H_ + +#include "../api.h" +#include "ILogSink.h" + +#include <boost/thread.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/thread/tss.hpp> + +#include <vector> +#include <map> +#if defined(_WIN32) || defined(_LIBCPP_VERSION) +#include <unordered_map> +#else +#include <tr1/unordered_map> +#endif +namespace avg { + +class ThreadProfiler; +typedef boost::shared_ptr<ThreadProfiler> ThreadProfilerPtr; +class ProfilingZone; +typedef boost::shared_ptr<ProfilingZone> ProfilingZonePtr; +class ProfilingZoneID; + +class AVG_API ThreadProfiler +{ +public: + static ThreadProfiler* get(); + static void kill(); + ThreadProfiler(); + virtual ~ThreadProfiler(); + void setLogCategory(category_t category); + + void start(); + void restart(); + void startZone(const ProfilingZoneID& zoneID); + void stopZone(const ProfilingZoneID& zoneID); + void dumpStatistics(); + void reset(); + int getNumZones(); + + const std::string& getName() const; + void setName(const std::string& sName); + +private: + ProfilingZonePtr addZone(const ProfilingZoneID& zoneID); + std::string m_sName; + +#if defined(_WIN32) || defined(_LIBCPP_VERSION) + typedef std::unordered_map<const ProfilingZoneID*, ProfilingZonePtr> ZoneMap; +#else + typedef std::tr1::unordered_map<const ProfilingZoneID*, ProfilingZonePtr> ZoneMap; +#endif + typedef std::vector<ProfilingZonePtr> ZoneVector; + ZoneMap m_ZoneMap; + ZoneVector m_ActiveZones; + ZoneVector m_Zones; + bool m_bRunning; + category_t m_LogCategory; + + static boost::thread_specific_ptr<ThreadProfiler*> s_pInstance; +}; + +} + +#endif diff --git a/src/base/TimeSource.cpp b/src/base/TimeSource.cpp new file mode 100644 index 0000000..e90575d --- /dev/null +++ b/src/base/TimeSource.cpp @@ -0,0 +1,128 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "TimeSource.h" + +#include "Logger.h" +#include "Exception.h" + +#ifdef _WIN32 +#include <time.h> +#include <sys/timeb.h> +#include <windows.h> +#include <Mmsystem.h> +#else +#include <sys/time.h> +#endif +#include <sys/stat.h> +#include <sys/types.h> + +#include <errno.h> +#include <assert.h> +#include <iostream> +#include <sstream> +#include <unistd.h> + +using namespace std; + +namespace avg { + +TimeSource* TimeSource::m_pTimeSource = 0; + +TimeSource * TimeSource::get() +{ + if (!m_pTimeSource) { +#ifdef _WIN32 + TIMECAPS tc; + UINT wTimerRes; + MMRESULT err = timeGetDevCaps(&tc, sizeof(TIMECAPS)); + AVG_ASSERT(err == TIMERR_NOERROR); + wTimerRes = max(tc.wPeriodMin, 1); + timeBeginPeriod(wTimerRes); +#endif + m_pTimeSource = new TimeSource; + } + return m_pTimeSource; +} + +TimeSource::TimeSource() +{ +#ifdef __APPLE__ + mach_timebase_info(&m_TimebaseInfo); +#endif +} + +TimeSource::~TimeSource() +{ +} + +long long TimeSource::getCurrentMillisecs() +{ + return getCurrentMicrosecs()/1000; +} + +long long TimeSource::getCurrentMicrosecs() +{ +#ifdef _WIN32 + return (long long)(timeGetTime())*1000; +#else +#ifdef __APPLE__ + long long systemTime = mach_absolute_time(); + return (systemTime * m_TimebaseInfo.numer/m_TimebaseInfo.denom)/1000; +#else + struct timespec now; + int rc = clock_gettime(CLOCK_MONOTONIC, &now); + assert(rc == 0); + return ((long long)now.tv_sec)*1000000+now.tv_nsec/1000; +#endif +#endif +} + +void TimeSource::sleepUntil(long long targetTime) +{ + long long now = getCurrentMillisecs(); +#ifdef __APPLE__ + if (targetTime > now) { + msleep(targetTime-now); + } +#else + while (now<targetTime) { + if (targetTime-now<=2) { + msleep(0); + } else { + msleep(int(targetTime-now-2)); + } + now = getCurrentMillisecs(); + } +#endif +} + +void msleep(int millisecs) +{ +#if _WIN32 + Sleep(millisecs); +#else + usleep((long long)(millisecs)*1000); +#endif +} + +} + diff --git a/src/base/TimeSource.h b/src/base/TimeSource.h new file mode 100644 index 0000000..a4ca9ae --- /dev/null +++ b/src/base/TimeSource.h @@ -0,0 +1,60 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _TimeSource_H_ +#define _TimeSource_H_ + +#include "../api.h" + +#ifdef __APPLE__ +#include <mach/mach_time.h> +#endif + +namespace avg { + + +// This class is a monotonic time source with an undefined start time. Time is guarranteed +// to increase monotonically. The time source has no jumps and does not go backwards, +// even if system time is changed. +class AVG_API TimeSource { +public: + static TimeSource* get(); + virtual ~TimeSource(); + + long long getCurrentMillisecs(); + long long getCurrentMicrosecs(); + + void sleepUntil(long long targetTime); + +private: + TimeSource(); +#ifdef __APPLE__ + mach_timebase_info_data_t m_TimebaseInfo; +#endif + + static TimeSource* m_pTimeSource; +}; + +void AVG_API msleep(int millisecs); + +} + +#endif diff --git a/src/base/Triangle.cpp b/src/base/Triangle.cpp new file mode 100644 index 0000000..7efe9f7 --- /dev/null +++ b/src/base/Triangle.cpp @@ -0,0 +1,105 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "Triangle.h" + +#include "GLMHelper.h" + +#include <math.h> + +namespace avg { + +Triangle::Triangle(const glm::vec2& P0, const glm::vec2& P1, const glm::vec2& P2) + : p0(P0), + p1(P1), + p2(P2) +{ +} + +Triangle::Triangle() +{ +} + +bool Triangle::operator ==(const Triangle & tri) const +{ + return (p0 == tri.p0 && p1 == tri.p1 && p2 == tri.p2); +} + +bool Triangle::isInside(const glm::vec2& pt) const +{ +/* Slower func that only works for cw triangles. + + glm::vec2 a = p2-p1; + glm::vec2 bp = pt-p1; + float aCROSSbp = a.x*bp.y - a.y*bp.x; + if (aCROSSbp < 0.0) { + return false; + } + + glm::vec2 b = p0-p2; + glm::vec2 cp = pt-p2; + float bCROSScp = b.x*cp.y - b.y*cp.x; + if (bCROSScp < 0.0) { + return false; + } + + glm::vec2 c = p1-p0; + glm::vec2 ap = pt-p0; + float cCROSSap = c.x*ap.y - c.y*ap.x; + return cCROSSap >= 0.0; +*/ + glm::vec2 v0 = p2 - p0; + glm::vec2 v1 = p1 - p0; + glm::vec2 v2 = pt - p0; + + float dot00 = glm::dot(v0, v0); + float dot01 = glm::dot(v0, v1); + float dot02 = glm::dot(v0, v2); + float dot11 = glm::dot(v1, v1); + float dot12 = glm::dot(v1, v2); + + float invDenom = 1 / (dot00 * dot11 - dot01 * dot01); + float u = (dot11 * dot02 - dot01 * dot12) * invDenom; + float v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + return (u > 0) && (v > 0) && (u + v < 1); + +} + +float Triangle::getArea() const +{ + return fabs((((p1.x-p0.x)*(p2.y-p0.y)) - ((p1.y-p0.y)*(p2.x-p0.x)))/2); +} + +bool Triangle::isClockwise() const +{ + return ((p1.x-p0.x)*(p2.y-p0.y)) - ((p1.y-p0.y)*(p2.x-p0.x)) < 0; +} + +std::ostream& operator<<(std::ostream& os, const Triangle& tri) +{ + os << "(" << tri.p0 << "," << tri.p1 << "," << tri.p2 << ")"; + return os; +} + + +} + diff --git a/src/base/Triangle.h b/src/base/Triangle.h new file mode 100644 index 0000000..21ad35f --- /dev/null +++ b/src/base/Triangle.h @@ -0,0 +1,52 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _Triangle_H_ +#define _Triangle_H_ + +#include "../api.h" + +#include "../glm/glm.hpp" + +#include <iostream> + +namespace avg { + +struct AVG_API Triangle { +public: + glm::vec2 p0; + glm::vec2 p1; + glm::vec2 p2; + + Triangle(const glm::vec2& P0, const glm::vec2& P1, const glm::vec2& P2); + Triangle(); + + bool operator ==(const Triangle & tri) const; + bool isInside(const glm::vec2& pt) const; + float getArea() const; + bool isClockwise() const; +}; + +std::ostream& operator<<(std::ostream& os, const Triangle& tri); + +} + +#endif diff --git a/src/base/UTF8String.cpp b/src/base/UTF8String.cpp new file mode 100644 index 0000000..4855364 --- /dev/null +++ b/src/base/UTF8String.cpp @@ -0,0 +1,62 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "UTF8String.h" + +#include <iostream> + +using namespace std; + +namespace avg { + +UTF8String::UTF8String() +{ +} + +UTF8String::UTF8String(const string& s) + : string(s) +{ +} + +UTF8String::UTF8String(const char * psz) + : string(psz) +{ + +} + +UTF8String& UTF8String::operator =(const string& s) +{ + *dynamic_cast<string*>(this) = s; + return *this; +} + +UTF8String& UTF8String::operator =(const char* psz) +{ + *dynamic_cast<string*>(this) = psz; + return *this; +} + +std::size_t hash_value(const avg::UTF8String& x) +{ + boost::hash<std::string> hasher; + return hasher(x); +}; +} diff --git a/src/base/UTF8String.h b/src/base/UTF8String.h new file mode 100644 index 0000000..3cee69d --- /dev/null +++ b/src/base/UTF8String.h @@ -0,0 +1,46 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _UTF8String_H_ +#define _UTF8String_H_ + +#include "../api.h" +#include <boost/functional/hash.hpp> +#include <string> + +namespace avg { + +class AVG_TEMPLATE_API UTF8String: public std::string +{ +public: + UTF8String(); + UTF8String(const std::string& s); + UTF8String(const char * psz); + + UTF8String& operator =(const std::string& s); + UTF8String& operator =(const char * psz); + +}; + +std::size_t hash_value(const avg::UTF8String& x); + +} +#endif diff --git a/src/base/WideLine.cpp b/src/base/WideLine.cpp new file mode 100644 index 0000000..84f4096 --- /dev/null +++ b/src/base/WideLine.cpp @@ -0,0 +1,53 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "WideLine.h" + +#include "GLMHelper.h" + +namespace avg { + +WideLine::WideLine(const glm::vec2& p0, const glm::vec2& p1, float width) + : pt0(p0), + pt1(p1) +{ + glm::vec2 m = glm::normalize(pt1-pt0); + glm::vec2 w = glm::vec2(m.y, -m.x)*(width/2); + pl0 = p0-w; + pr0 = p0+w; + pl1 = p1-w; + pr1 = p1+w; + dir = glm::vec2(w.y, -w.x); +} + +float WideLine::getLen() const +{ + return glm::length(pt1-pt0); +} + +std::ostream& operator<<(std::ostream& os, const WideLine& line) +{ + os << "(" << line.pt0 << "," << line.pt1 << ")"; + return os; +} + +} + diff --git a/src/base/WideLine.h b/src/base/WideLine.h new file mode 100644 index 0000000..28584ef --- /dev/null +++ b/src/base/WideLine.h @@ -0,0 +1,48 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _WideLine_H_ +#define _WideLine_H_ + +#include "../api.h" + +#include "../glm/glm.hpp" + +#include <iostream> + +namespace avg { + +struct AVG_API WideLine { + WideLine(const glm::vec2& p0, const glm::vec2& p1, float width); + + float getLen() const; + + glm::vec2 pt0, pt1; + glm::vec2 pl0, pl1; + glm::vec2 pr0, pr1; + glm::vec2 dir; +}; + +std::ostream& operator<<(std::ostream& os, const WideLine& line); + +} + +#endif diff --git a/src/base/WorkerThread.cpp b/src/base/WorkerThread.cpp new file mode 100644 index 0000000..f2efb0a --- /dev/null +++ b/src/base/WorkerThread.cpp @@ -0,0 +1,41 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "WorkerThread.h" + +#include "OSHelper.h" + +namespace avg { + +using namespace std; + +#ifdef linux +void printAffinityMask(cpu_set_t& mask) +{ + for (int i=0; i<32; ++i) { + cerr << int(CPU_ISSET(i, &mask)); + } + cerr << endl; +} +#endif + +} + diff --git a/src/base/WorkerThread.h b/src/base/WorkerThread.h new file mode 100644 index 0000000..c4cc3c4 --- /dev/null +++ b/src/base/WorkerThread.h @@ -0,0 +1,169 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _WorkerThread_H_ +#define _WorkerThread_H_ + +#include "../api.h" +#include "Command.h" +#include "Exception.h" +#include "Logger.h" +#include "Queue.h" +#include "ThreadHelper.h" +#include "ThreadProfiler.h" +#include "CmdQueue.h" + +#include <boost/shared_ptr.hpp> + +#include <iostream> + +namespace avg { + + +template<class DERIVED_THREAD> +class AVG_TEMPLATE_API WorkerThread { +public: + typedef Command<DERIVED_THREAD> Cmd; + typedef typename boost::shared_ptr<Cmd> CmdPtr; + typedef CmdQueue<DERIVED_THREAD> CQueue; + typedef typename boost::shared_ptr<CQueue> CQueuePtr; + + WorkerThread(const std::string& sName, CQueue& CmdQ, + category_t logCategory=Logger::category::PROFILE); + WorkerThread(WorkerThread const& other); + virtual ~WorkerThread(); + void operator()(); + + void waitForCommand(); + void stop(); + +protected: + int getNumCmdsInQueue() const; + +private: + virtual bool init(); + virtual bool work() = 0; + virtual void deinit() {}; + + void processCommands(); + + std::string m_sName; + bool m_bShouldStop; + CQueue& m_CmdQ; + category_t m_LogCategory; +}; + +template<class DERIVED_THREAD> +WorkerThread<DERIVED_THREAD>::WorkerThread(const std::string& sName, CQueue& CmdQ, + category_t logCategory) + : m_sName(sName), + m_bShouldStop(false), + m_CmdQ(CmdQ), + m_LogCategory(logCategory) +{ +} + +template<class DERIVED_THREAD> +WorkerThread<DERIVED_THREAD>::WorkerThread(WorkerThread const& other) + : m_CmdQ(other.m_CmdQ) +{ + m_sName = other.m_sName; + m_bShouldStop = other.m_bShouldStop; + m_LogCategory = other.m_LogCategory; +} + +template<class DERIVED_THREAD> +WorkerThread<DERIVED_THREAD>::~WorkerThread() +{ +} + +template<class DERIVED_THREAD> +void WorkerThread<DERIVED_THREAD>::operator()() +{ + try { + setAffinityMask(false); + ThreadProfiler* pProfiler = ThreadProfiler::get(); + pProfiler->setName(m_sName); + pProfiler->setLogCategory(m_LogCategory); + bool bOK; + bOK = init(); + if (!bOK) { + return; + } + pProfiler->start(); + while (!m_bShouldStop) { + bOK = work(); + if (!bOK) { + m_bShouldStop = true; + } + if (!m_bShouldStop) { + processCommands(); + } + } + deinit(); + pProfiler->dumpStatistics(); + pProfiler->kill(); + } catch (const Exception& e) { + AVG_LOG_ERROR("Uncaught exception in thread " << m_sName << ": " << e.getStr()); + throw; + } +} + +template<class DERIVED_THREAD> +void WorkerThread<DERIVED_THREAD>::waitForCommand() +{ + CmdPtr pCmd = m_CmdQ.pop(true); + pCmd->execute(dynamic_cast<DERIVED_THREAD*>(this)); +} + +template<class DERIVED_THREAD> +void WorkerThread<DERIVED_THREAD>::stop() +{ + m_bShouldStop = true; +} + +template<class DERIVED_THREAD> +int WorkerThread<DERIVED_THREAD>::getNumCmdsInQueue() const +{ + return m_CmdQ.size(); +} + +template<class DERIVED_THREAD> +bool WorkerThread<DERIVED_THREAD>::init() +{ + return true; +} + +template<class DERIVED_THREAD> +void WorkerThread<DERIVED_THREAD>::processCommands() +{ + CmdPtr pCmd = m_CmdQ.pop(false); + while (pCmd && !m_bShouldStop) { + pCmd->execute(dynamic_cast<DERIVED_THREAD*>(this)); + if (!m_bShouldStop) { + pCmd = m_CmdQ.pop(false); + } + } +} + +} + +#endif diff --git a/src/base/XMLHelper.cpp b/src/base/XMLHelper.cpp new file mode 100644 index 0000000..6f362e8 --- /dev/null +++ b/src/base/XMLHelper.cpp @@ -0,0 +1,225 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "XMLHelper.h" +#include "Exception.h" +#include "Logger.h" + +#include <libxml/parserInternals.h> +#include <cstring> +#include <iostream> + +using namespace std; + +namespace avg { + +string getXmlChildrenAsString(const xmlDocPtr xmlDoc, const xmlNodePtr& xmlNode) +{ + string s; + xmlBufferPtr pBuffer = xmlBufferCreate(); + xmlNodeDump(pBuffer, xmlDoc, xmlNode, 0, 0); + + s = (const char *)xmlBufferContent(pBuffer); + size_t StartPos = s.find('>')+1; + size_t EndPos = s.rfind('<')-1; + if (StartPos > EndPos) { + s = ""; + } else { + s = s.substr(StartPos, EndPos-StartPos+1); + } + xmlBufferFree(pBuffer); + return s; +} + +static xmlExternalEntityLoader DefaultLoaderProc = 0; +static std::map<string, string> g_DTDMap; + +xmlParserInputPtr +DTDExternalEntityLoader(const char *pURL, const char *pID, xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr ret; + /* lookup for the fileID depending on ID */ + std::map<string, string>::iterator it = g_DTDMap.find(pURL); + + if (it != g_DTDMap.end()) { + ret = xmlNewStringInputStream(ctxt, (const xmlChar *)(it->second.c_str())); + return(ret); + } else { + ret = DefaultLoaderProc(pURL, pID, ctxt); + return(ret); + } +} + +void registerDTDEntityLoader(const string& sID, const string& sDTD) +{ + g_DTDMap[sID] = sDTD; + if (!DefaultLoaderProc) { + DefaultLoaderProc = xmlGetExternalEntityLoader(); + } + xmlSetExternalEntityLoader(DTDExternalEntityLoader); +} + + +XMLParser::XMLParser() + : m_SchemaParserCtxt(0), + m_Schema(0), + m_SchemaValidCtxt(0), + m_DTD(0), + m_DTDValidCtxt(0), + m_Doc(0) +{ + xmlPedanticParserDefault(1); + xmlSetGenericErrorFunc(this, errorOutputFunc); + xmlDoValidityCheckingDefaultValue = 0; +} + +XMLParser::~XMLParser() +{ + if (m_Schema) { + xmlSchemaFree(m_Schema); + } + if (m_SchemaParserCtxt) { + xmlSchemaFreeParserCtxt(m_SchemaParserCtxt); + } + if (m_SchemaValidCtxt) { + xmlSchemaFreeValidCtxt(m_SchemaValidCtxt); + } + if (m_DTD) { + xmlFreeDtd(m_DTD); + } + if (m_DTDValidCtxt) { + xmlFreeValidCtxt(m_DTDValidCtxt); + } + if (m_Doc) { + xmlFreeDoc(m_Doc); + } + xmlSetGenericErrorFunc(0, 0); +} + +void XMLParser::setSchema(const string& sSchema, const string& sSchemaName) +{ + AVG_ASSERT(!m_SchemaParserCtxt); + AVG_ASSERT(!m_Schema); + AVG_ASSERT(!m_SchemaValidCtxt); + AVG_ASSERT(!m_DTD); + AVG_ASSERT(!m_DTDValidCtxt); + + m_SchemaParserCtxt = xmlSchemaNewMemParserCtxt(sSchema.c_str(), sSchema.length()); + checkError(!m_SchemaParserCtxt, sSchemaName); + + m_Schema = xmlSchemaParse(m_SchemaParserCtxt); + checkError(!m_Schema, sSchemaName); + + m_SchemaValidCtxt = xmlSchemaNewValidCtxt(m_Schema); + checkError(!m_SchemaValidCtxt, sSchemaName); +} + +void XMLParser::setDTD(const std::string& sDTD, const std::string& sDTDName) +{ + AVG_ASSERT(!m_SchemaParserCtxt); + AVG_ASSERT(!m_Schema); + AVG_ASSERT(!m_SchemaValidCtxt); + AVG_ASSERT(!m_DTD); + AVG_ASSERT(!m_DTDValidCtxt); + + registerDTDEntityLoader("memory.dtd", sDTD.c_str()); + string sDTDFName = "memory.dtd"; + m_DTD = xmlParseDTD(NULL, (const xmlChar*) sDTDFName.c_str()); + checkError(!m_DTD, sDTDName); + + m_DTDValidCtxt = xmlNewValidCtxt(); + checkError(!m_DTDValidCtxt, sDTDName); + m_DTDValidCtxt->error = xmlParserValidityError; + m_DTDValidCtxt->warning = xmlParserValidityWarning; +} + +void XMLParser::parse(const string& sXML, const string& sXMLName) +{ + if (m_Doc) { + xmlFreeDoc(m_Doc); + } + m_Doc = xmlParseMemory(sXML.c_str(), int(sXML.length())); + checkError(!m_Doc, sXMLName); + + bool bOK = true; + if (m_SchemaValidCtxt) { + int err = xmlSchemaValidateDoc(m_SchemaValidCtxt, m_Doc); + AVG_ASSERT(err != -1); + bOK = (err == 0); + } + if (m_DTD) { + int err = xmlValidateDtd(m_DTDValidCtxt, m_Doc, m_DTD); + bOK = (err != 0); + } + if (!bOK) { + xmlFreeDoc(m_Doc); + m_Doc = 0; + checkError(true, sXMLName); + } +} + +xmlDocPtr XMLParser::getDoc() +{ + AVG_ASSERT(m_Doc); + return m_Doc; +} + +xmlNodePtr XMLParser::getRootNode() +{ + AVG_ASSERT(m_Doc); + return xmlDocGetRootElement(m_Doc); +} + +void XMLParser::errorOutputFunc(void * ctx, const char * msg, ...) +{ + va_list args; + va_start(args, msg); + ((XMLParser*)ctx)->internalErrorHandler(msg, args); + va_end(args); +} + +void XMLParser::internalErrorHandler(const char * msg, va_list args) +{ + char psz[1024]; + vsnprintf(psz, 1024, msg, args); + m_sError += psz; +} + +void XMLParser::checkError(bool bError, const string& sXMLName) +{ + if (bError) { + string sError = "Error parsing "+sXMLName+".\n"; + sError += m_sError; + m_sError = ""; + throw (Exception(AVG_ERR_XML_PARSE, sError)); + } +} + +void validateXml(const string& sXML, const string& sSchema, const string& sXMLName, + const string& sSchemaName) +{ + XMLParser parser; + parser.setSchema(sSchema, sSchemaName); + + parser.parse(sXML, sXMLName); +} + +} diff --git a/src/base/XMLHelper.h b/src/base/XMLHelper.h new file mode 100644 index 0000000..e258de2 --- /dev/null +++ b/src/base/XMLHelper.h @@ -0,0 +1,78 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef _XMLHelper_H_ +#define _XMLHelper_H_ + +#include "../api.h" + +#include <libxml/parser.h> +#include <libxml/xmlwriter.h> +#include <libxml/xmlschemas.h> + +#include <string> +#include <map> +#include <sstream> + +namespace avg { + +std::string getXmlChildrenAsString(const xmlDocPtr xmlDoc, const xmlNodePtr& xmlNode); + +void registerDTDEntityLoader(const std::string& sID, const std::string& sDTD); + +class XMLParser +{ +public: + XMLParser(); + virtual ~XMLParser(); + + void setSchema(const std::string& sSchema, const std::string& sSchemaName); + void setDTD(const std::string& sDTD, const std::string& sDTDName); + void parse(const std::string& sXML, const std::string& sXMLName); + + xmlDocPtr getDoc(); + xmlNodePtr getRootNode(); + +private: + static void errorOutputFunc(void * ctx, const char * msg, ...); + void internalErrorHandler(const char * msg, va_list args); + + void checkError(bool bError, const std::string& sXMLName); + + xmlSchemaParserCtxtPtr m_SchemaParserCtxt; + xmlSchemaPtr m_Schema; + xmlSchemaValidCtxtPtr m_SchemaValidCtxt; + + xmlDtdPtr m_DTD; + xmlValidCtxtPtr m_DTDValidCtxt; + + xmlDocPtr m_Doc; + + std::string m_sError; +}; + +void validateXml(const std::string& sXML, const std::string& sSchema, + const std::string& sXMLName, const std::string& sSchemaName); + +} + +#endif + diff --git a/src/base/testbase.cpp b/src/base/testbase.cpp new file mode 100644 index 0000000..57faf36 --- /dev/null +++ b/src/base/testbase.cpp @@ -0,0 +1,1024 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "DAG.h" +#include "Queue.h" +#include "Command.h" +#include "WorkerThread.h" +#include "ObjectCounter.h" +#include "triangulate/Triangulate.h" +#include "GLMHelper.h" +#include "GeomHelper.h" +#include "OSHelper.h" +#include "FileHelper.h" +#include "StringHelper.h" +#include "MathHelper.h" +#include "CubicSpline.h" +#include "BezierCurve.h" +#include "Signal.h" +#include "Backtrace.h" +#include "WideLine.h" +#include "Rect.h" +#include "Triangle.h" +#include "TestSuite.h" +#include "TimeSource.h" +#include "XMLHelper.h" +#include "Logger.h" + +#include <boost/thread/thread.hpp> + +#include <boost/bind.hpp> + +#include <iostream> +#include <sstream> +#include <stdio.h> +#include <stdlib.h> + +using namespace avg; +using namespace std; +using namespace boost; + +class DAGTest: public Test +{ +public: + DAGTest() + : Test("DAGTest", 2) + { + } + + void runTests() + { + { + DAG dag; + + dag.addNode(1, set<long>()); + long outgoing2[] = {1}; + dag.addNode(0, makeOutgoing(1, outgoing2)); + + long expected[] = {0, 1}; + checkResults(&dag, expected); + } + { + DAG dag; + + dag.addNode(2, set<long>()); + long outgoing2[] = {1}; + dag.addNode(0, makeOutgoing(1, outgoing2)); + long outgoing3[] = {2}; + dag.addNode(1, makeOutgoing(1, outgoing3)); + + long expected[] = {0, 1, 2}; + checkResults(&dag, expected); + } + { + DAG dag; + + long outgoing2[] = {1}; + dag.addNode(0, makeOutgoing(1, outgoing2)); + dag.addNode(2, set<long>()); + long outgoing3[] = {2}; + dag.addNode(1, makeOutgoing(1, outgoing3)); + + long expected[] = {0, 1, 2}; + checkResults(&dag, expected); + } + { + DAG dag; + + dag.addNode(2, set<long>()); + long outgoing2[] = {1, 2}; + dag.addNode(0, makeOutgoing(1, outgoing2)); + long outgoing3[] = {2}; + dag.addNode(1, makeOutgoing(1, outgoing3)); + + long expected[] = {0, 1, 2}; + checkResults(&dag, expected); + } + { + DAG dag; + + long outgoing2[] = {1}; + dag.addNode(0, makeOutgoing(1, outgoing2)); + long outgoing3[] = {0}; + dag.addNode(1, makeOutgoing(1, outgoing3)); + + bool bExceptionThrown = false; + long expected[] = {0, 1, 2}; + try { + checkResults(&dag, expected); + } catch (const Exception&) { + bExceptionThrown = true; + } + TEST(bExceptionThrown); + } + } + +private: + set<long> makeOutgoing(int n, long ids[]) + { + set<long> v; + for (int i=0; i<n; ++i) { + v.insert(ids[i]); + } + return v; + } + + void checkResults(DAG* pDAG, long expected[]) + { + vector<long> results; + pDAG->sort(results); + + for (unsigned i=0; i<results.size(); ++i) { + QUIET_TEST(results[i] == expected[i]); + } + } +}; + +class QueueTest: public Test +{ +public: + QueueTest() + : Test("QueueTest", 2) + { + } + + void runTests() + { + runSingleThreadTests(); + runMultiThreadTests(); + } + +private: + typedef Queue<int>::QElementPtr ElemPtr; + + void runSingleThreadTests() + { + Queue<string> q; + typedef Queue<string>::QElementPtr ElemPtr; + TEST(q.empty()); + q.push(ElemPtr(new string("1"))); + TEST(q.size() == 1); + TEST(!q.empty()); + q.push(ElemPtr(new string("2"))); + q.push(ElemPtr(new string("3"))); + TEST(q.size() == 3); + TEST(*q.pop() == "1"); + TEST(*q.pop() == "2"); + q.push(ElemPtr(new string("4"))); + TEST(*q.pop() == "3"); + TEST(*q.peek() == "4"); + TEST(*q.pop() == "4"); + TEST(q.empty()); + ElemPtr pElem = q.pop(false); + TEST(!pElem); + } + + void runMultiThreadTests() + { + { + Queue<int> q(10); + thread pusher(boost::bind(&pushThread, &q, 100)); + thread popper(boost::bind(&popThread, &q, 100)); + pusher.join(); + popper.join(); + TEST(q.empty()); + } + { + Queue<int> q(10); + thread pusher1(boost::bind(&pushThread, &q, 100)); + thread pusher2(boost::bind(&pushThread, &q, 100)); + thread popper(boost::bind(&popThread, &q, 200)); + pusher1.join(); + pusher2.join(); + popper.join(); + TEST(q.empty()); + } + { + Queue<int> q(10); + thread pusher(boost::bind(&pushClearThread, &q, 100)); + thread popper(boost::bind(&popClearThread, &q)); + pusher.join(); + popper.join(); + TEST(q.empty()); + } + } + + static void pushThread(Queue<int>* pq, int numPushes) + { + for (int i=0; i<numPushes; ++i) { + pq->push(ElemPtr(new int(i))); + msleep(1); + } + } + + static void popThread(Queue<int>* pq, int numPops) + { + for (int i=0; i<numPops; ++i) { + pq->peek(); + pq->pop(); + msleep(3); + } + } + + static void pushClearThread(Queue<int>* pq, int numPushes) + { + typedef Queue<int>::QElementPtr ElemPtr; + for (int i=0; i<numPushes; ++i) { + pq->push(ElemPtr(new int(i))); + if (i%7 == 0) { + pq->clear(); + } + msleep(1); + } + pq->push(ElemPtr(new int(-1))); + } + + static void popClearThread(Queue<int>* pq) + { + ElemPtr pElem; + do { + pElem = pq->pop(); + } while (*pElem != -1); + } +}; + +class TestWorkerThread: public WorkerThread<TestWorkerThread> +{ +public: + TestWorkerThread(CQueue& cmdQ, int* pNumFuncCalls, int* pIntParam, + string* pStringParam) + : WorkerThread<TestWorkerThread>("Thread1", cmdQ), + m_pNumFuncCalls(pNumFuncCalls), + m_pIntParam(pIntParam), + m_pStringParam(pStringParam) + { + } + + bool init() + { + (*m_pNumFuncCalls)++; + return true; + } + + bool work() + { + (*m_pNumFuncCalls)++; + waitForCommand(); + return true; + } + + void deinit() + { + (*m_pNumFuncCalls)++; + } + + void doSomething(int i, std::string s) + { + *m_pIntParam = i; + *m_pStringParam = s; + } + +private: + int * m_pNumFuncCalls; + int * m_pIntParam; + std::string * m_pStringParam; +}; + + +class WorkerThreadTest: public Test +{ +public: + WorkerThreadTest() + : Test("WorkerThreadTest", 2) + { + } + + void runTests() + { + typedef TestWorkerThread::CmdPtr CmdPtr; + TestWorkerThread::CQueue cmdQ; + boost::thread* pTestThread; + int numFuncCalls = 0; + int intParam = 0; + std::string stringParam; + cmdQ.pushCmd(boost::bind(&TestWorkerThread::doSomething, _1, 23, "foo")); + cmdQ.pushCmd(boost::bind(&TestWorkerThread::stop, _1)); + pTestThread = new boost::thread(TestWorkerThread(cmdQ, &numFuncCalls, + &intParam, &stringParam)); + pTestThread->join(); + delete pTestThread; + TEST(numFuncCalls == 3); + TEST(intParam == 23); + TEST(stringParam == "foo"); + } +}; + + +class DummyClass +{ +public: + DummyClass() + { + ObjectCounter::get()->incRef(&typeid(*this)); + } + + virtual ~DummyClass() + { + ObjectCounter::get()->decRef(&typeid(*this)); + } + + int i; +}; + + +class ObjectCounterTest: public Test { +public: + ObjectCounterTest() + : Test("ObjectCounterTest", 2) + { + } + + void runTests() + { + TEST(ObjectCounter::get()->getCount(&typeid(DummyClass)) == 0); + { + DummyClass dummy1; + DummyClass dummy2; + TEST(ObjectCounter::get()->getCount(&typeid(dummy1)) == 2); + } + TEST(ObjectCounter::get()->getCount(&typeid(DummyClass)) == 0); + } +}; + + +// The following pragmas avoid a compiler warning (potential division by 0) +#ifdef _MSC_VER +#pragma optimize("", off) +#pragma warning(push) +#pragma warning(disable:4723) +#endif +class GeomTest: public Test +{ +public: + GeomTest() + : Test("GeomTest", 2) + { + } + + void runTests() + { + // TODO: Move to a separate math test once we're done here. + TEST(almostEqual(invSqrt(1), 1)); + TEST(almostEqual(invSqrt(4), 0.5)); + + { + LineSegment l1(glm::vec2(0,0), glm::vec2(2,2)); + LineSegment l2(glm::vec2(2,0), glm::vec2(0,2)); + TEST(lineSegmentsIntersect(l1, l2)); + TEST(lineSegmentsIntersect(l2, l1)); + } + { + LineSegment l1(glm::vec2(0,0), glm::vec2(0,2)); + LineSegment l2(glm::vec2(2,0), glm::vec2(2,2)); + TEST(!lineSegmentsIntersect(l1, l2)); + } + { + LineSegment l1(glm::vec2(0,0), glm::vec2(2,0)); + LineSegment l2(glm::vec2(0,2), glm::vec2(2,2)); + TEST(!lineSegmentsIntersect(l1, l2)); + } + { + LineSegment l1(glm::vec2(0,0), glm::vec2(2,0)); + TEST(l1.isPointOver(glm::vec2(1,23))); + TEST(l1.isPointOver(glm::vec2(1.9,-5))); + TEST(!l1.isPointOver(glm::vec2(-1,1))); + TEST(!l1.isPointOver(glm::vec2(3,-1))); + } + { + glm::vec2 pt0(glm::vec2(1,1)); + glm::vec2 pt1(glm::vec2(1,3)); + glm::vec2 pt2(glm::vec2(1,-2)); + vector<glm::vec2> poly; + poly.push_back(glm::vec2(0,0)); + poly.push_back(glm::vec2(2,0)); + poly.push_back(glm::vec2(2,2)); + poly.push_back(glm::vec2(0,2)); + TEST(pointInPolygon(pt0, poly)); + TEST(!pointInPolygon(pt1, poly)); + TEST(!pointInPolygon(pt2, poly)); + poly.push_back(glm::vec2(2,1)); + TEST(!pointInPolygon(pt0, poly)); + } + { + glm::vec2 p1(glm::vec2(0,0)); + glm::vec2 v1(glm::vec2(1,1)); + glm::vec2 p2(glm::vec2(2,1)); + glm::vec2 v2(glm::vec2(1,0)); + TEST(getLineLineIntersection(p1, v1, p2, v2) == glm::vec2(1,1)); + } + TEST(almostEqual(getRotatedPivot(glm::vec2(10,0), M_PI, glm::vec2(15,5)), + glm::vec2(20,10))); + TEST(almostEqual(getRotatedPivot(glm::vec2(10,0), M_PI*0.5, glm::vec2(15,5)), + glm::vec2(20,0))); + TEST(almostEqual(getRotatedPivot(glm::vec2(10,0), M_PI*1.5, glm::vec2(15,5)), + glm::vec2(10,10))); + TEST(almostEqual(getRotatedPivot(glm::vec2(10,0), M_PI*2, glm::vec2(15,5)), + glm::vec2(10,0))); + TEST(almostEqual(getRotatedPivot(glm::vec2(23,0), M_PI*0.5), glm::vec2(0,23))); + + { + // TODO: More tests + FRect(0,0,10,10); + } + } +}; +#ifdef _MSC_VER +#pragma warning(pop) +#pragma optimize("", on) +#endif + + +class TriangleTest: public Test +{ +public: + TriangleTest() + : Test("TriangleTest", 2) + { + } + + void runTests() + { + Triangle tri(glm::vec2(0,0), glm::vec2(4,4), glm::vec2(4,8)); + TEST(tri.isInside(glm::vec2(3,4))); + TEST(!tri.isInside(glm::vec2(1,4))); + TEST(!tri.isInside(glm::vec2(2,1))); + TEST(!tri.isInside(glm::vec2(-2,5))); + TEST(!tri.isInside(glm::vec2(5,5))); + tri = Triangle(glm::vec2(0,0), glm::vec2(4,8), glm::vec2(4,4)); + TEST(tri.isInside(glm::vec2(3,4))); + + glm::vec2 polyArray[] = {glm::vec2(0,0), glm::vec2(8,2), glm::vec2(9,0), glm::vec2(9,3), + glm::vec2(1,1), glm::vec2(0,3)}; + + Vec2Vector poly = vectorFromCArray(6, polyArray); + vector<unsigned int> triangulation; + triangulatePolygon(triangulation, poly); + + TEST(triangulation.size() == 4*3); + unsigned int baselineIndexes[] = {5,0,4, 1,4,0, 4,1,3, 1,2,3}; + TEST(triangulation == vectorFromCArray(12, baselineIndexes)); +/* + for (unsigned int i=0; i<triangulation.size(); i++) { + cerr << i << ":" << triangulation[i] << endl; + } +*/ + } + +}; + + +class FileTest: public Test +{ +public: + FileTest() + : Test("FileTest", 2) + { + } + + void runTests() + { + TEST(getPath("/foo/bar.txt") == "/foo/"); + TEST(getFilenamePart("/foo/bar.txt") == "bar.txt"); + } +}; + + +class OSTest: public Test +{ +public: + OSTest() + : Test("OSTest", 2) + { + } + + void runTests() + { + cerr << getAvgLibPath() << endl; + TEST(getAvgLibPath() != ""); +#ifdef __APPLE__ + TEST(getMemoryUsage() != 0); +#endif + } +}; + + +class StringTest: public Test +{ +public: + StringTest() + : Test("StringTest", 2) + { + } + + void runTests() + { + TEST(stringToInt("5") == 5); + TEST(almostEqual(stringToFloat("5.5"), 5.5f)); + TEST(stringToBool("False") == false); + bool bExceptionThrown = false; + try { + stringToInt("5a"); + } catch (const Exception& e) { + if (e.getCode() == AVG_ERR_TYPE ) { + bExceptionThrown = true; + } + } + TEST(bExceptionThrown); + TEST(stringToVec2(" ( 3.4 , 2.1 ) ") == glm::vec2(3.4f, 2.1f)); + vector<float> v; + fromString("(1,2,3,4,5)", v); + TEST(v.size() == 5 && v[0] == 1 && v[4] == 5); + v.clear(); + fromString("()", v); + TEST(v.size() == 0); + } +}; + + +class SplineTest: public Test +{ +public: + SplineTest() + : Test("SplineTest", 2) + { + } + + void runTests() + { + { + float xd[] = {0,1,2,3}; + vector<float> x = vectorFromCArray(4, xd); + float yd[] = {3,2,1,0}; + vector<float> y = vectorFromCArray(4, yd); + CubicSpline spline(x, y); + TEST(almostEqual(spline.interpolate(-1), 4)); + TEST(almostEqual(spline.interpolate(0), 3)); + TEST(almostEqual(spline.interpolate(0.5), 2.5)); + TEST(almostEqual(spline.interpolate(3), 0)); + TEST(almostEqual(spline.interpolate(3.5), -0.5)); + } + { + float xd[] = {2,4,6,8}; + vector<float> x = vectorFromCArray(4, xd); + float yd[] = {0,1,3,6}; + vector<float> y = vectorFromCArray(4, yd); + CubicSpline spline(x, y); + TEST(almostEqual(spline.interpolate(0), -1)); + TEST(almostEqual(spline.interpolate(2), 0)); + TEST(spline.interpolate(3) < 0.5); + TEST(spline.interpolate(3) > 0); + TEST(spline.interpolate(7) > 4); + TEST(spline.interpolate(7) < 5); + TEST(almostEqual(spline.interpolate(8), 6)); + TEST(almostEqual(spline.interpolate(10), 9)); + } + { + float xd[] = {0,1,1}; + vector<float> x = vectorFromCArray(3, xd); + float yd[] = {1,2,1}; + vector<float> y = vectorFromCArray(3, yd); + bool bExceptionThrown = false; + try { + CubicSpline spline(x, y); + } catch (const Exception&) { + bExceptionThrown = true; + } + TEST(bExceptionThrown); + } +/* + { + float xd[] = {0,1,2}; + vector<float> x = vectorFromCArray(3, xd); + float yd[] = {1,2,1}; + vector<float> y = vectorFromCArray(3, yd); + CubicSpline spline(x, y, true); + TEST(almostEqual(spline.interpolate(0), 1)); + TEST(almostEqual(spline.interpolate(0.5), 1.5)); + TEST(almostEqual(spline.interpolate(2), 1)); + TEST(almostEqual(spline.interpolate(3), 2)); + } +*/ + } +}; + + +class BezierCurveTest: public Test +{ +public: + BezierCurveTest() + : Test("BezierCurveTest", 2) + { + } + + void runTests() + { + BezierCurve curve(glm::vec2(0,0), glm::vec2(1,0), glm::vec2(1,1), glm::vec2(0,1)); + TEST(almostEqual(curve.interpolate(0), glm::vec2(0,0))); + TEST(almostEqual(curve.getDeriv(0), glm::vec2(3, 0))); + TEST(almostEqual(curve.interpolate(1), glm::vec2(0,1))); + TEST(almostEqual(curve.getDeriv(1), glm::vec2(-3, 0))); + TEST(almostEqual(curve.interpolate(0.5), glm::vec2(0.75,0.5))); + } +}; + + +class WideLineTest: public Test +{ +public: + WideLineTest() + : Test("WideLineTest", 2) + { + } + + void runTests() + { + WideLine line(glm::vec2(0,0), glm::vec2(4,3), 2); + TEST(almostEqual(line.getLen(), 5)); + } +}; + + +class Listener +{ +public: + Listener(Signal<Listener>& signal) + : m_Signal(signal), + m_bFuncCalled(false) + { + } + + virtual ~Listener() + {} + + virtual void func() + { + m_bFuncCalled = true; + } + + bool funcCalled() const + { + return m_bFuncCalled; + } + + void reset() + { + m_bFuncCalled = false; + } + +protected: + Signal<Listener>& m_Signal; + +private: + bool m_bFuncCalled; +}; + + +class DisconnectingSelfListener: public Listener +{ +public: + DisconnectingSelfListener(Signal<Listener>& signal) + : Listener(signal) + { + } + + virtual void func() + { + Listener::func(); + m_Signal.disconnect(this); + } +}; + + +class DisconnectingOtherListener: public Listener +{ +public: + DisconnectingOtherListener(Signal<Listener>& signal, Listener* pOther) + : Listener(signal), + m_pOther(pOther) + { + } + + virtual void func() + { + Listener::func(); + if (m_pOther) { + m_Signal.disconnect(m_pOther); + m_pOther = 0; + } + } + +private: + Listener* m_pOther; +}; + + +class ConnectingOtherListener: public Listener +{ +public: + ConnectingOtherListener(Signal<Listener>& signal, Listener* pOther) + : Listener(signal), + m_pOther(pOther) + { + } + + virtual void func() + { + Listener::func(); + if (m_pOther) { + m_Signal.connect(m_pOther); + m_pOther = 0; + } + } + +private: + Listener* m_pOther; +}; + + +class SignalTest: public Test +{ +public: + SignalTest() + : Test("SignalTest", 2) + { + } + + void runTests() + { + Signal<Listener> s(&Listener::func); + Listener l1(s); + Listener l2(s); + s.connect(&l1); + s.connect(&l2); + s.emit(); + TEST(l1.funcCalled() && l2.funcCalled()); + l1.reset(); + l2.reset(); + + s.disconnect(&l1); + s.emit(); + TEST(!(l1.funcCalled()) && l2.funcCalled()); + l2.reset(); + + { + DisconnectingSelfListener disconnecter(s); + s.connect(&disconnecter); + s.emit(); + TEST(l2.funcCalled() && disconnecter.funcCalled()); + TEST(s.getNumListeners() == 1); + l2.reset(); + disconnecter.reset(); + + s.emit(); + TEST(l2.funcCalled() && !(disconnecter.funcCalled())); + l2.reset(); + } + { + DisconnectingOtherListener disconnecter(s, &l2); + s.connect(&disconnecter); + s.emit(); + TEST(l2.funcCalled() && disconnecter.funcCalled()); + TEST(s.getNumListeners() == 1); + l2.reset(); + disconnecter.reset(); + + s.emit(); + TEST(!(l2.funcCalled()) && disconnecter.funcCalled()); + s.disconnect(&disconnecter); + } + { + ConnectingOtherListener connecter(s, &l2); + s.connect(&connecter); + s.emit(); + TEST(l2.funcCalled() && connecter.funcCalled()); + TEST(s.getNumListeners() == 2); + l2.reset(); + connecter.reset(); + + s.emit(); + TEST(l2.funcCalled() && connecter.funcCalled()); + } + } +}; + + +class BacktraceTest: public Test +{ +public: + BacktraceTest() + : Test("BacktraceTest", 2) + { + } + + void runTests() + { + vector<string> sFuncs; + getBacktrace(sFuncs); +#ifndef _WIN32 + TEST(sFuncs[0].find("runTests") != string::npos); +#endif + } +}; + + +class PolygonTest: public Test +{ +public: + PolygonTest() + : Test("PolygonTest", 2) + { + } + + void runTests() + { + glm::vec2 polyArray[] = {glm::vec2(30,0), glm::vec2(40,20), glm::vec2(60,30), + glm::vec2(40,40), glm::vec2(30,60), glm::vec2(20,40), glm::vec2(0,30), + glm::vec2(20,20)}; + + Vec2Vector poly = vectorFromCArray(8, polyArray); + vector<unsigned int> triangulation; + triangulatePolygon(triangulation, poly); + + TEST(triangulation.size() == 6*3); + unsigned int baselineIndexes[] = {6,7,5, 5,7,1, 7,0,1, 5,1,3, 3,1,2, 4,5,3}; + TEST(triangulation == vectorFromCArray(18, baselineIndexes)); +/* + for (unsigned int i=0; i<triangulation.size(); i++) { + cerr << i << ":" << triangulation[i] << endl; + }/ +*/ + } + +}; + + +class XmlParserTest: public Test +{ +public: + XmlParserTest() + : Test("XmlParserTest", 2) + { + } + + void runTests() + { + string sXmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<shiporder orderid=\"889923\">" + " <orderperson>John Smith</orderperson>" + "</shiporder>"; + + { + string sSchema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" + "<xs:element name=\"shiporder\">" + " <xs:complexType>" + " <xs:sequence>" + " <xs:element name=\"orderperson\" type=\"xs:string\"/>" + " </xs:sequence>" + " <xs:attribute name=\"orderid\" type=\"xs:string\" use=\"required\"/>" + " </xs:complexType>" + "</xs:element>" + "</xs:schema>"; + + XMLParser parser; + parser.setSchema(sSchema, "shiporder.xsd"); + parser.parse(sXmlString, "shiporder.xml"); + } + { + string sDTD = + "<!ELEMENT shiporder (orderperson)* >" + "<!ATTLIST shiporder" + " orderid CDATA #IMPLIED>" + "<!ELEMENT orderperson (#PCDATA) >"; + XMLParser parser; + parser.setDTD(sDTD, "shiporder.dtd"); + parser.parse(sXmlString, "shiporder.xml"); + } + } +}; + + +class StandardLoggerTest: public Test +{ +public: + StandardLoggerTest() + : Test("StandardLoggerTest", 2) + { + } + + void runTests() + { + std::stringstream buffer; + std::streambuf *sbuf = std::cerr.rdbuf(); + Logger *logger = Logger::get(); + { + std::cerr.rdbuf(buffer.rdbuf()); + string msg("Test log message"); + AVG_TRACE(Logger::category::NONE, Logger::severity::WARNING, msg); + std::cerr.rdbuf(sbuf); + TEST(buffer.str().find(msg) != string::npos); + buffer.str(string()); + + std::cerr.rdbuf(buffer.rdbuf()); + AVG_TRACE(Logger::category::NONE, Logger::severity::DEBUG, msg); + std::cerr.rdbuf(sbuf); + std::cout << buffer.str(); + TEST(buffer.str().find(msg) == string::npos); + buffer.str(string()); + } + { + std::cerr.rdbuf(buffer.rdbuf()); + category_t CUSTOM_CAT = logger->configureCategory("CUSTOM_CAT 1"); + string msg("CUSTOM_CAT LOG"); + AVG_TRACE(CUSTOM_CAT, Logger::severity::WARNING, msg); + std::cerr.rdbuf(sbuf); + TEST(buffer.str().find(msg) != string::npos); + buffer.str(string()); + } + { + std::cerr.rdbuf(buffer.rdbuf()); + category_t CUSTOM_CAT = logger->configureCategory("CUSTOM_CAT 1", + Logger::severity::CRITICAL); + string msg_info("CUSTOM_CAT LOG INFO"); + AVG_TRACE(CUSTOM_CAT, Logger::severity::WARNING, msg_info); + std::cerr.rdbuf(sbuf); + TEST(buffer.str().find(msg_info) == string::npos); + buffer.str(string()); + + std::cerr.rdbuf(buffer.rdbuf()); + string msg_critical("CUSTOM_CAT LOG CRITICAL"); + AVG_TRACE(CUSTOM_CAT, Logger::severity::CRITICAL, msg_critical); + std::cerr.rdbuf(sbuf); + TEST(buffer.str().find(msg_critical) != string::npos); + buffer.str(string()); + } + } +}; + +class BaseTestSuite: public TestSuite +{ +public: + BaseTestSuite() + : TestSuite("BaseTestSuite") + { + addTest(TestPtr(new DAGTest)); + addTest(TestPtr(new QueueTest)); + addTest(TestPtr(new WorkerThreadTest)); + addTest(TestPtr(new ObjectCounterTest)); + addTest(TestPtr(new GeomTest)); + addTest(TestPtr(new TriangleTest)); + addTest(TestPtr(new FileTest)); + addTest(TestPtr(new OSTest)); + addTest(TestPtr(new StringTest)); + addTest(TestPtr(new SplineTest)); + addTest(TestPtr(new BezierCurveTest)); + addTest(TestPtr(new SignalTest)); + addTest(TestPtr(new BacktraceTest)); + addTest(TestPtr(new PolygonTest)); + addTest(TestPtr(new XmlParserTest)); + addTest(TestPtr(new StandardLoggerTest)); + } +}; + + +int main(int nargs, char** args) +{ + BaseTestSuite suite; + suite.runTests(); + bool bOK = suite.isOk(); + + if (bOK) { + return 0; + } else { + return 1; + } +} + diff --git a/src/base/triangulate/AdvancingFront.cpp b/src/base/triangulate/AdvancingFront.cpp new file mode 100644 index 0000000..d14f1d3 --- /dev/null +++ b/src/base/triangulate/AdvancingFront.cpp @@ -0,0 +1,104 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +// +// Based on Poly2Tri algorithm. +// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors +// http://code.google.com/p/poly2tri/ +// + +#include "AdvancingFront.h" + +namespace avg { + +AdvancingFront::AdvancingFront(Node& head, Node& tail) +{ + m_Head = &head; + m_Tail = &tail; + m_SearchNode = &head; +} + +Node* AdvancingFront::locateNode(const double& x) +{ + Node* node = m_SearchNode; + + if (x < node->m_Value) { + while ((node = node->m_Prev) != NULL) { + if (x >= node->m_Value) { + m_SearchNode = node; + return node; + } + } + } else { + while ((node = node->m_Next) != NULL) { + if (x < node->m_Value) { + m_SearchNode = node->m_Prev; + return node->m_Prev; + } + } + } + return NULL; +} + +Node* AdvancingFront::findSearchNode(const double& x) +{ + // TO DO: implement BST index + return m_SearchNode; +} + +Node* AdvancingFront::locatePoint(const Point* point) +{ + const double px = point->m_X; + Node* node = findSearchNode(px); + const double nx = node->m_Point->m_X; + + if (px == nx) { + if (point != node->m_Point) { + // We might have two nodes with same x value for a short time + if (point == node->m_Prev->m_Point) { + node = node->m_Prev; + } else if (point == node->m_Next->m_Point) { + node = node->m_Next; + } else { + assert(0); + } + } + } else if (px < nx) { + while ((node = node->m_Prev) != NULL) { + if (point == node->m_Point) { + break; + } + } + } else { + while ((node = node->m_Next) != NULL) { + if (point == node->m_Point) + break; + } + } + if (node) + m_SearchNode = node; + return node; +} + +AdvancingFront::~AdvancingFront() {} + +} + diff --git a/src/base/triangulate/AdvancingFront.h b/src/base/triangulate/AdvancingFront.h new file mode 100644 index 0000000..3bb0d5b --- /dev/null +++ b/src/base/triangulate/AdvancingFront.h @@ -0,0 +1,118 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +// +// Based on Poly2Tri algorithm. +// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors +// http://code.google.com/p/poly2tri/ +// + +#ifndef ADVANCED_FRONT_H +#define ADVANCED_FRONT_H + +#include "Shapes.h" + +namespace avg { + +struct Node; + +struct Node +{ + Point* m_Point; + TriangulationTriangle* m_Triangle; + + Node* m_Next; + Node* m_Prev; + + double m_Value; + + Node() : m_Point(NULL), m_Triangle(NULL), m_Next(NULL), m_Prev(NULL), m_Value(0) + {} + + Node(Point& p) : m_Point(&p), m_Triangle(NULL), m_Next(NULL), m_Prev(NULL), m_Value(p.m_X) + {} + + Node(Point& p, TriangulationTriangle& t) : m_Point(&p), m_Triangle(&t), m_Next(NULL), m_Prev(NULL), m_Value(p.m_X) + {} + +}; + + +class AdvancingFront +{ + +public: + +AdvancingFront(Node& head, Node& tail); + +~AdvancingFront(); + +Node* head(); +void setHead(Node* node); +Node* tail(); +void setTail(Node* node); +Node* search(); +void setSearch(Node* node); + +/// Locate insertion point along advancing front +Node* locateNode(const double& x); + +Node* locatePoint(const Point* point); + +private: + +Node* m_Head, *m_Tail, *m_SearchNode; + +Node* findSearchNode(const double& x); +}; + + +inline Node* AdvancingFront::head() +{ + return m_Head; +} +inline void AdvancingFront::setHead(Node* node) +{ + m_Head = node; +} + +inline Node* AdvancingFront::tail() +{ + return m_Tail; +} +inline void AdvancingFront::setTail(Node* node) +{ + m_Tail = node; +} + +inline Node* AdvancingFront::search() +{ + return m_SearchNode; +} + +inline void AdvancingFront::setSearch(Node* node) +{ + m_SearchNode = node; +} + +} + +#endif diff --git a/src/base/triangulate/Makefile.am b/src/base/triangulate/Makefile.am new file mode 100644 index 0000000..9381e58 --- /dev/null +++ b/src/base/triangulate/Makefile.am @@ -0,0 +1,8 @@ +AM_CPPFLAGS = -I.. @XML2_CFLAGS@ @PTHREAD_CFLAGS@ +ALL_H = Triangulate.h Shapes.h Utils.h \ + AdvancingFront.h Sweep.h SweepContext.h + +noinst_LTLIBRARIES = libtriangulate.la +libtriangulate_la_SOURCES = Triangulate.cpp Shapes.cpp \ + AdvancingFront.cpp Sweep.cpp SweepContext.cpp \ + $(ALL_H) diff --git a/src/base/triangulate/Shapes.cpp b/src/base/triangulate/Shapes.cpp new file mode 100644 index 0000000..08e2e13 --- /dev/null +++ b/src/base/triangulate/Shapes.cpp @@ -0,0 +1,353 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +// +// Based on Poly2Tri algorithm. +// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors +// http://code.google.com/p/poly2tri/ +// + +#include "Shapes.h" +#include <iostream> + +namespace avg { + +TriangulationTriangle::TriangulationTriangle(Point& a, Point& b, Point& c) +{ + m_Points[0] = &a; + m_Points[1] = &b; + m_Points[2] = &c; + m_Neighbors[0] = NULL; + m_Neighbors[1] = NULL; + m_Neighbors[2] = NULL; + m_ConstrainedEdge[0] = m_ConstrainedEdge[1] = m_ConstrainedEdge[2] = false; + m_DelaunayEdge[0] = m_DelaunayEdge[1] = m_DelaunayEdge[2] = false; + m_Interior = false; +} + +// Update neighbor pointers +void TriangulationTriangle::markNeighbor(Point* p1, Point* p2, + TriangulationTriangle* t) +{ + if ((p1 == m_Points[2] && p2 == m_Points[1]) + || (p1 == m_Points[1] && p2 == m_Points[2])) { + m_Neighbors[0] = t; + } else if ((p1 == m_Points[0] && p2 == m_Points[2]) + || (p1 == m_Points[2] && p2 == m_Points[0])) { + m_Neighbors[1] = t; + } else if ((p1 == m_Points[0] && p2 == m_Points[1]) + || (p1 == m_Points[1] && p2 == m_Points[0])) { + m_Neighbors[2] = t; + } else { + assert(0); + } + +} + +// Exhaustive search to update neighbor pointers +void TriangulationTriangle::markNeighbor(TriangulationTriangle& t) +{ + if (t.contains(m_Points[1], m_Points[2])) { + m_Neighbors[0] = &t; + t.markNeighbor(m_Points[1], m_Points[2], this); + } else if (t.contains(m_Points[0], m_Points[2])) { + m_Neighbors[1] = &t; + t.markNeighbor(m_Points[0], m_Points[2], this); + } else if (t.contains(m_Points[0], m_Points[1])) { + m_Neighbors[2] = &t; + t.markNeighbor(m_Points[0], m_Points[1], this); + } +} + +void TriangulationTriangle::clear() +{ + TriangulationTriangle *t; + for (int i = 0; i < 3; i++) { + t = m_Neighbors[i]; + if (t != NULL) { + t->clearNeighbor(this); + } + } + clearNeighbors(); + m_Points[0] = m_Points[1] = m_Points[2] = NULL; +} + +void TriangulationTriangle::clearNeighbor(TriangulationTriangle *triangle) +{ + if (m_Neighbors[0] == triangle) { + m_Neighbors[0] = NULL; + } else if (m_Neighbors[1] == triangle) { + m_Neighbors[1] = NULL; + } else { + m_Neighbors[2] = NULL; + } +} + +void TriangulationTriangle::clearNeighbors() +{ + m_Neighbors[0] = NULL; + m_Neighbors[1] = NULL; + m_Neighbors[2] = NULL; +} + +void TriangulationTriangle::clearDelunayEdges() +{ + m_DelaunayEdge[0] = m_DelaunayEdge[1] = m_DelaunayEdge[2] = false; +} + +Point* TriangulationTriangle::oppositePoint(TriangulationTriangle& t, + Point& p) { + Point *cw = t.pointCW(p); + return pointCW(*cw); +} + +// Legalized triangle by rotating clockwise around point(0) +void TriangulationTriangle::legalize(Point& point) +{ + m_Points[1] = m_Points[0]; + m_Points[0] = m_Points[2]; + m_Points[2] = &point; +} + +// Legalize triagnle by rotating clockwise around oPoint +void TriangulationTriangle::legalize(Point& opoint, Point& npoint) +{ + if (&opoint == m_Points[0]) { + m_Points[1] = m_Points[0]; + m_Points[0] = m_Points[2]; + m_Points[2] = &npoint; + } else if (&opoint == m_Points[1]) { + m_Points[2] = m_Points[1]; + m_Points[1] = m_Points[0]; + m_Points[0] = &npoint; + } else if (&opoint == m_Points[2]) { + m_Points[0] = m_Points[2]; + m_Points[2] = m_Points[1]; + m_Points[1] = &npoint; + } else { + assert(0); + } +} + +unsigned int TriangulationTriangle::index(const Point* p) +{ + if (p == m_Points[0]) { + return 0; + } else if (p == m_Points[1]) { + return 1; + } else if (p == m_Points[2]) { + return 2; + } + assert(0); + return 0; +} + +unsigned int TriangulationTriangle::edgeIndex(const Point* p1, const Point* p2) +{ + if (m_Points[0] == p1) { + if (m_Points[1] == p2) { + return 2; + } else if (m_Points[2] == p2) { + return 1; + } + } else if (m_Points[1] == p1) { + if (m_Points[2] == p2) { + return 0; + } else if (m_Points[0] == p2) { + return 2; + } + } else if (m_Points[2] == p1) { + if (m_Points[0] == p2) { + return 1; + } else if (m_Points[1] == p2) { + return 0; + } + } + return -1; +} + +void TriangulationTriangle::markConstrainedEdge(const int index) +{ + m_ConstrainedEdge[index] = true; +} + +void TriangulationTriangle::markConstrainedEdge(Edge& edge) +{ + markConstrainedEdge(edge.m_P, edge.m_Q); +} + +void TriangulationTriangle::markConstrainedEdge(Point* p, Point* q) +{ + if ((q == m_Points[0] && p == m_Points[1]) + || (q == m_Points[1] && p == m_Points[0])) { + m_ConstrainedEdge[2] = true; + } else if ((q == m_Points[0] && p == m_Points[2]) + || (q == m_Points[2] && p == m_Points[0])) { + m_ConstrainedEdge[1] = true; + } else if ((q == m_Points[1] && p == m_Points[2]) + || (q == m_Points[2] && p == m_Points[1])) { + m_ConstrainedEdge[0] = true; + } +} + +// The point counter-clockwise to given point +Point* TriangulationTriangle::pointCW(Point& point) +{ + if (&point == m_Points[0]) { + return m_Points[2]; + } else if (&point == m_Points[1]) { + return m_Points[0]; + } else if (&point == m_Points[2]) { + return m_Points[1]; + } + assert(0); + return 0; // Silence compiler warning +} + +Point* TriangulationTriangle::pointCCW(Point& point) +{ + if (&point == m_Points[0]) { + return m_Points[1]; + } else if (&point == m_Points[1]) { + return m_Points[2]; + } else if (&point == m_Points[2]) { + return m_Points[0]; + } + assert(0); + return 0; // Silence compiler warning +} + +TriangulationTriangle* TriangulationTriangle::neighborCW(Point& point) +{ + if (&point == m_Points[0]) { + return m_Neighbors[1]; + } else if (&point == m_Points[1]) { + return m_Neighbors[2]; + } + return m_Neighbors[0]; +} + +TriangulationTriangle* TriangulationTriangle::neighborCCW(Point& point) +{ + if (&point == m_Points[0]) { + return m_Neighbors[2]; + } else if (&point == m_Points[1]) { + return m_Neighbors[0]; + } + return m_Neighbors[1]; +} + +bool TriangulationTriangle::getConstrainedEdgeCCW(Point& p) +{ + if (&p == m_Points[0]) { + return m_ConstrainedEdge[2]; + } else if (&p == m_Points[1]) { + return m_ConstrainedEdge[0]; + } + return m_ConstrainedEdge[1]; +} + +bool TriangulationTriangle::getConstrainedEdgeCW(Point& p) +{ + if (&p == m_Points[0]) { + return m_ConstrainedEdge[1]; + } else if (&p == m_Points[1]) { + return m_ConstrainedEdge[2]; + } + return m_ConstrainedEdge[0]; +} + +void TriangulationTriangle::setConstrainedEdgeCCW(Point& p, bool ce) +{ + if (&p == m_Points[0]) { + m_ConstrainedEdge[2] = ce; + } else if (&p == m_Points[1]) { + m_ConstrainedEdge[0] = ce; + } else { + m_ConstrainedEdge[1] = ce; + } +} + +void TriangulationTriangle::setConstrainedEdgeCW(Point& p, bool ce) +{ + if (&p == m_Points[0]) { + m_ConstrainedEdge[1] = ce; + } else if (&p == m_Points[1]) { + m_ConstrainedEdge[2] = ce; + } else { + m_ConstrainedEdge[0] = ce; + } +} + +bool TriangulationTriangle::getDelunayEdgeCCW(Point& p) +{ + if (&p == m_Points[0]) { + return m_DelaunayEdge[2]; + } else if (&p == m_Points[1]) { + return m_DelaunayEdge[0]; + } + return m_DelaunayEdge[1]; +} + +bool TriangulationTriangle::getDelunayEdgeCW(Point& p) +{ + if (&p == m_Points[0]) { + return m_DelaunayEdge[1]; + } else if (&p == m_Points[1]) { + return m_DelaunayEdge[2]; + } + return m_DelaunayEdge[0]; +} + +void TriangulationTriangle::setDelunayEdgeCCW(Point& p, bool e) +{ + if (&p == m_Points[0]) { + m_DelaunayEdge[2] = e; + } else if (&p == m_Points[1]) { + m_DelaunayEdge[0] = e; + } else { + m_DelaunayEdge[1] = e; + } +} + +void TriangulationTriangle::setDelunayEdgeCW(Point& p, bool e) +{ + if (&p == m_Points[0]) { + m_DelaunayEdge[1] = e; + } else if (&p == m_Points[1]) { + m_DelaunayEdge[2] = e; + } else { + m_DelaunayEdge[0] = e; + } +} + +TriangulationTriangle& TriangulationTriangle::neighborAcross(Point& opoint) +{ + if (&opoint == m_Points[0]) { + return *m_Neighbors[0]; + } else if (&opoint == m_Points[1]) { + return *m_Neighbors[1]; + } + return *m_Neighbors[2]; +} + +} + diff --git a/src/base/triangulate/Shapes.h b/src/base/triangulate/Shapes.h new file mode 100644 index 0000000..0417d7c --- /dev/null +++ b/src/base/triangulate/Shapes.h @@ -0,0 +1,296 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +// +// Based on Poly2Tri algorithm. +// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors +// http://code.google.com/p/poly2tri/ +// + +#ifndef SHAPES_H +#define SHAPES_H + +#include <vector> +#include <cstddef> +#include <assert.h> +#include <cmath> + +namespace avg { + +struct Edge; + +struct Point +{ + double m_X, m_Y; + int m_Index; + + /// The edges this point constitutes an upper ending point + std::vector<Edge*> m_EdgeList; + + /// Default constructor does nothing (for performance). + Point() { + m_X = 0.0; + m_Y = 0.0; + m_Index = 0; + } + + Point(double x, double y, int index) : + m_X(x), m_Y(y), m_Index(index) {} + + void set_zero() + { + m_X = 0.0; + m_Y = 0.0; + } + + void set(double x_, double y_) + { + m_X = x_; + m_Y = y_; + } + + Point operator -() const + { + Point v; + v.set(-m_X, -m_Y); + return v; + } + + void operator +=(const Point& v) + { + m_X += v.m_X; + m_Y += v.m_Y; + } + + void operator -=(const Point& v) + { + m_X -= v.m_X; + m_Y -= v.m_Y; + } + + void operator *=(double a) + { + m_X *= a; + m_Y *= a; + } + + double length() const + { + return sqrt(m_X * m_X + m_Y * m_Y); + } + + /// Convert this point into a unit point. Returns the Length. + double normalize() + { + double len = length(); + m_X /= len; + m_Y /= len; + return len; + } + +}; + + +// Represents a simple polygon's edge +struct Edge +{ + Point* m_P, *m_Q; + + Edge(Point& p1, Point& p2) :m_P(&p1), m_Q(&p2) + { + if (p1.m_Y > p2.m_Y) { + m_Q = &p1; + m_P = &p2; + } else if (p1.m_Y == p2.m_Y) { + if (p1.m_X > p2.m_X) { + m_Q = &p1; + m_P = &p2; + } else if (p1.m_X == p2.m_X) { + // Repeat points + assert(false); + } + } + m_Q->m_EdgeList.push_back(this); + } +}; + + +class TriangulationTriangle +{ + +public: + + TriangulationTriangle(Point& a, Point& b, Point& c); + +/// Flags to determine if an edge is a Constrained edge + bool m_ConstrainedEdge[3]; +/// Flags to determine if an edge is a Delauney edge + bool m_DelaunayEdge[3]; + + Point* getPoint(const int& index); + Point* pointCW(Point& point); + Point* pointCCW(Point& point); + Point* oppositePoint(TriangulationTriangle& t, Point& p); + + TriangulationTriangle* getNeighbor(const int& index); + void markNeighbor(Point* p1, Point* p2, TriangulationTriangle* t); + void markNeighbor(TriangulationTriangle& t); + + void markConstrainedEdge(const int index); + void markConstrainedEdge(Edge& edge); + void markConstrainedEdge(Point* p, Point* q); + + unsigned int index(const Point* p); + unsigned int edgeIndex(const Point* p1, const Point* p2); + + TriangulationTriangle* neighborCW(Point& point); + TriangulationTriangle* neighborCCW(Point& point); + bool getConstrainedEdgeCCW(Point& p); + bool getConstrainedEdgeCW(Point& p); + void setConstrainedEdgeCCW(Point& p, bool ce); + void setConstrainedEdgeCW(Point& p, bool ce); + bool getDelunayEdgeCCW(Point& p); + bool getDelunayEdgeCW(Point& p); + void setDelunayEdgeCCW(Point& p, bool e); + void setDelunayEdgeCW(Point& p, bool e); + + bool contains(Point* p); + bool contains(const Edge& e); + bool contains(Point* p, Point* q); + void legalize(Point& point); + void legalize(Point& opoint, Point& npoint); + + void clear(); + void clearNeighbor(TriangulationTriangle *triangle); + void clearNeighbors(); + void clearDelunayEdges(); + + inline bool isInterior(); + inline void isInterior(bool b); + + TriangulationTriangle& neighborAcross(Point& opoint); + +private: + + Point* m_Points[3]; + + TriangulationTriangle* m_Neighbors[3]; + + bool m_Interior; +}; + +inline bool cmp(const Point* a, const Point* b) +{ + if (a->m_Y < b->m_Y) { + return true; + } else if (a->m_Y == b->m_Y) { + // Make sure q is point with greater x value + if (a->m_X < b->m_X) { + return true; + } + } + return false; +} +/* + inline Point operator +(const Point& a, const Point& b) + { + return Point(a.x + b.x, a.y + b.y); + } + + inline Point operator -(const Point& a, const Point& b) + { + return Point(a.x - b.x, a.y - b.y); + } + + inline Point operator *(double s, const Point& a) + { + return Point(s * a.x, s * a.y, a.index); + } */ + +inline bool operator ==(const Point& a, const Point& b) +{ + return a.m_X == b.m_X && a.m_Y == b.m_Y; +} + +inline bool operator !=(const Point& a, const Point& b) +{ + return a.m_X != b.m_X && a.m_Y != b.m_Y; +} + +inline double dot(const Point& a, const Point& b) +{ + return a.m_X * b.m_X + a.m_Y * b.m_Y; +} + +inline double cross(const Point& a, const Point& b) +{ + return a.m_X * b.m_Y - a.m_Y * b.m_X; +} + +inline Point cross(const Point& a, double s) +{ + return Point(s * a.m_Y, -s * a.m_X, a.m_Index); +} + +inline Point cross(const double s, const Point& a) +{ + return Point(-s * a.m_Y, s * a.m_X, a.m_Index); +} + +inline Point* TriangulationTriangle::getPoint(const int& index) +{ + return m_Points[index]; +} + +inline TriangulationTriangle* TriangulationTriangle::getNeighbor( + const int& index) +{ + return m_Neighbors[index]; +} + +inline bool TriangulationTriangle::contains(Point* p) +{ + return p == m_Points[0] || p == m_Points[1] || p == m_Points[2]; +} + +inline bool TriangulationTriangle::contains(const Edge& e) +{ + return contains(e.m_P) && contains(e.m_Q); +} + +inline bool TriangulationTriangle::contains(Point* p, Point* q) +{ + return contains(p) && contains(q); +} + +inline bool TriangulationTriangle::isInterior() +{ + return m_Interior; +} + +inline void TriangulationTriangle::isInterior(bool b) +{ + m_Interior = b; +} + +} + +#endif diff --git a/src/base/triangulate/Sweep.cpp b/src/base/triangulate/Sweep.cpp new file mode 100644 index 0000000..2655cb0 --- /dev/null +++ b/src/base/triangulate/Sweep.cpp @@ -0,0 +1,796 @@ +//
+// libavg - Media Playback Engine.
+// Copyright (C) 2003-2014 Ulrich von Zadow +//
+// 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 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Current versions can be found at www.libavg.de
+//
+
+//
+// Based on Poly2Tri algorithm.
+// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+// http://code.google.com/p/poly2tri/
+//
+
+#include <stdexcept>
+#include "Sweep.h"
+#include "SweepContext.h"
+#include "AdvancingFront.h"
+#include "Utils.h"
+
+namespace avg {
+
+void Sweep::Triangulate(SweepContext& sc)
+{
+ arrayCount = 0;
+ for (unsigned int i = 0; i < (unsigned)sc.pointCount(); i++) {
+ m_Nodes.push_back(new Node());
+ }
+ sc.initTriangulation();
+ sc.createAdvancingFront();
+ // Sweep points; build mesh
+ sweepPoints(sc);
+ // Clean up
+ finalizationPolygon(sc);
+}
+
+void Sweep::sweepPoints(SweepContext& sc)
+{
+ for (int i = 1; i < sc.pointCount(); i++) {
+ Point& point = *sc.getPoint(i);
+ Node* node = &pointEvent(sc, point);
+ for (unsigned int i = 0; i < point.m_EdgeList.size(); i++) {
+ edgeEvent(sc, point.m_EdgeList[i], node);
+ }
+ }
+}
+
+void Sweep::finalizationPolygon(SweepContext& sc)
+{
+ // Get an Internal triangle to start with
+ TriangulationTriangle* t = sc.front()->head()->m_Next->m_Triangle;
+ Point* p = sc.front()->head()->m_Next->m_Point;
+ while (!t->getConstrainedEdgeCW(*p)) {
+ t = t->neighborCCW(*p);
+ }
+
+ // Collect interior triangles constrained by edges
+ sc.meshClean(*t);
+}
+
+Node& Sweep::pointEvent(SweepContext& sc, Point& point)
+{
+ Node& node = sc.locateNode(point);
+ Node& new_node = newFrontTriangle(sc, point, node);
+
+ // Only need to check +epsilon since point never have smaller
+ // x value than node due to how we fetch nodes from the front
+ if (point.m_X <= node.m_Point->m_X + EPSILON) {
+ fill(sc, node);
+ }
+
+ //tcx.AddNode(new_node);
+
+ fillAdvancingFront(sc, new_node);
+ return new_node;
+}
+
+void Sweep::edgeEvent(SweepContext& sc, Edge* edge, Node* node)
+{
+ sc.m_EdgeEvent.m_ConstrainedEdge = edge;
+ sc.m_EdgeEvent.m_Right = (edge->m_P->m_X > edge->m_Q->m_X);
+
+ if (isEdgeSideOfTriangle(*node->m_Triangle, *edge->m_P, *edge->m_Q)) {
+ return;
+ }
+
+ // to do: integrate with flip process might give some better performance
+ // but for now this avoid the issue with cases that needs both flips and fills
+ fillEdgeEvent(sc, edge, node);
+ edgeEvent(sc, *edge->m_P, *edge->m_Q, node->m_Triangle, *edge->m_Q);
+}
+
+void Sweep::edgeEvent(SweepContext& sc, Point& ep, Point& eq,
+ TriangulationTriangle* triangle, Point& point)
+{
+ if (isEdgeSideOfTriangle(*triangle, ep, eq)) {
+ return;
+ }
+
+ Point* p1 = triangle->pointCCW(point);
+ Orientation o1 = orient2d(eq, *p1, ep);
+ if (o1 == COLLINEAR) {
+ if (triangle->contains(&eq, p1)) {
+ triangle->markConstrainedEdge(&eq, p1);
+ // We are modifying the constraint maybe it would be better to
+ // not change the given constraint and just keep a variable for the new constraint
+ sc.m_EdgeEvent.m_ConstrainedEdge->m_Q = p1;
+ triangle = &triangle->neighborAcross(point);
+ edgeEvent(sc, ep, *p1, triangle, *p1);
+ } else {
+ std::runtime_error("EdgeEvent - collinear points not supported");
+ assert(0);
+ }
+ return;
+ }
+
+ Point* p2 = triangle->pointCW(point);
+ Orientation o2 = orient2d(eq, *p2, ep);
+ if (o2 == COLLINEAR) {
+ if (triangle->contains(&eq, p2)) {
+ triangle->markConstrainedEdge(&eq, p2);
+ // We are modifying the constraint maybe it would be better to
+ // not change the given constraint and just keep a variable for the new constraint
+ sc.m_EdgeEvent.m_ConstrainedEdge->m_Q = p2;
+ triangle = &triangle->neighborAcross(point);
+ edgeEvent(sc, ep, *p2, triangle, *p2);
+ } else {
+ std::runtime_error("EdgeEvent - collinear points not supported");
+ assert(0);
+ }
+ return;
+ }
+
+ if (o1 == o2) {
+ // Need to decide if we are rotating CW or CCW to get to a triangle
+ // that will cross edge
+ if (o1 == CW) {
+ triangle = triangle->neighborCCW(point);
+ } else {
+ triangle = triangle->neighborCW(point);
+ }
+ edgeEvent(sc, ep, eq, triangle, point);
+ } else {
+ // This triangle crosses constraint so lets flippin start!
+ flipEdgeEvent(sc, ep, eq, triangle, point);
+ }
+}
+
+bool Sweep::isEdgeSideOfTriangle(TriangulationTriangle& triangle, Point& ep,
+ Point& eq)
+{
+ int index = triangle.edgeIndex(&ep, &eq);
+
+ if (index != -1) {
+ triangle.markConstrainedEdge(index);
+ TriangulationTriangle* t = triangle.getNeighbor(index);
+ if (t) {
+ t->markConstrainedEdge(&ep, &eq);
+ }
+ return true;
+ }
+ return false;
+}
+
+Node& Sweep::newFrontTriangle(SweepContext& sc, Point& point, Node& node)
+{
+ TriangulationTriangle* triangle = new TriangulationTriangle(point,
+ *node.m_Point, *node.m_Next->m_Point);
+
+ triangle->markNeighbor(*node.m_Triangle);
+ sc.addToMap(triangle);
+
+ Node* newNode = m_Nodes[arrayCount++]; //new Node(point);
+ newNode->m_Point = &point;
+ newNode->m_Value = point.m_X;
+// m_Nodes.push_back(newNode);
+
+ newNode->m_Next = node.m_Next;
+ newNode->m_Prev = &node;
+ node.m_Next->m_Prev = newNode;
+ node.m_Next = newNode;
+
+ if (!legalize(sc, *triangle)) {
+ sc.mapTriangleToNodes(*triangle);
+ }
+
+ return *newNode;
+}
+
+void Sweep::fill(SweepContext& sc, Node& node)
+{
+ TriangulationTriangle* triangle = new TriangulationTriangle(
+ *node.m_Prev->m_Point, *node.m_Point, *node.m_Next->m_Point);
+
+ // TO DO: should copy the constrained_edge value from neighbor triangles
+ // for now constrained_edge values are copied during the legalize
+ triangle->markNeighbor(*node.m_Prev->m_Triangle);
+ triangle->markNeighbor(*node.m_Triangle);
+
+ sc.addToMap(triangle);
+
+ // Update the advancing front
+ node.m_Prev->m_Next = node.m_Next;
+ node.m_Next->m_Prev = node.m_Prev;
+
+ // If it was legalized the triangle has already been mapped
+ if (!legalize(sc, *triangle)) {
+ sc.mapTriangleToNodes(*triangle);
+ }
+
+}
+
+void Sweep::fillAdvancingFront(SweepContext& sc, Node& n)
+{
+ Node* node = n.m_Next;
+
+ while (node->m_Next) {
+ double angle = holeAngle(*node);
+ if (angle > M_PI_2 || angle < -M_PI_2)
+ break;
+// ---------- LEAK FIX --------------
+// Fill(tcx, *node);
+// node = node->m_next;
+
+
+ Node *tmp = node;
+ node = node->m_Next;
+ fill(sc, *tmp);
+// ----------------------------------
+ }
+
+ node = n.m_Prev;
+
+ while (node->m_Prev) {
+ double angle = holeAngle(*node);
+ if (angle > M_PI_2 || angle < -M_PI_2)
+ break;
+ fill(sc, *node);
+ node = node->m_Prev;
+ }
+
+ if (n.m_Next && n.m_Next->m_Next) {
+ double angle = basinAngle(n);
+ if (angle < PI_3div4) {
+ fillBasin(sc, n);
+ }
+ }
+}
+
+double Sweep::basinAngle(Node& node)
+{
+ double ax = node.m_Point->m_X - node.m_Next->m_Next->m_Point->m_X;
+ double ay = node.m_Point->m_Y - node.m_Next->m_Next->m_Point->m_Y;
+ return atan2(ay, ax);
+}
+
+double Sweep::holeAngle(Node& node)
+{
+ /* Complex plane
+ * ab = cosA +i*sinA
+ * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx)
+ * atan2(y,x) computes the principal value of the argument function
+ * applied to the complex number x+iy
+ * Where x = ax*bx + ay*by
+ * y = ax*by - ay*bx
+ */
+ double ax = node.m_Next->m_Point->m_X - node.m_Point->m_X;
+ double ay = node.m_Next->m_Point->m_Y - node.m_Point->m_Y;
+ double bx = node.m_Prev->m_Point->m_X - node.m_Point->m_X;
+ double by = node.m_Prev->m_Point->m_Y - node.m_Point->m_Y;
+ return atan2(ax * by - ay * bx, ax * bx + ay * by);
+}
+
+bool Sweep::legalize(SweepContext& sc, TriangulationTriangle& t)
+{
+ // To legalize a triangle we start by finding if any of the three edges
+ // violate the Delaunay condition
+ for (int i = 0; i < 3; i++) {
+ if (t.m_DelaunayEdge[i])
+ continue;
+
+ TriangulationTriangle* ot = t.getNeighbor(i);
+
+ if (ot) {
+ Point* p = t.getPoint(i);
+ Point* op = ot->oppositePoint(t, *p);
+ int oi = ot->index(op);
+
+ // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization)
+ // then we should not try to legalize
+ if (ot->m_ConstrainedEdge[oi] || ot->m_DelaunayEdge[oi]) {
+ t.m_ConstrainedEdge[i] = ot->m_ConstrainedEdge[oi];
+ continue;
+ }
+
+ bool inside = incircle(*p, *t.pointCCW(*p), *t.pointCW(*p), *op);
+
+ if (inside) {
+ // Lets mark this shared edge as Delaunay
+ t.m_DelaunayEdge[i] = true;
+ ot->m_DelaunayEdge[oi] = true;
+
+ // Lets rotate shared edge one vertex CW to legalize it
+ rotateTrianglePair(t, *p, *ot, *op);
+
+ // We now got one valid Delaunay Edge shared by two triangles
+ // This gives us 4 new edges to check for Delaunay
+
+ // Make sure that triangle to node mapping is done only one time for a specific triangle
+ bool notLegalized = !legalize(sc, t);
+ if (notLegalized) {
+ sc.mapTriangleToNodes(t);
+ }
+
+ notLegalized = !legalize(sc, *ot);
+ if (notLegalized)
+ sc.mapTriangleToNodes(*ot);
+
+ // Reset the Delaunay edges, since they only are valid Delaunay edges
+ // until we add a new triangle or point.
+ // XX X: need to think about this. Can these edges be tried after we
+ // return to previous recursive level?
+ t.m_DelaunayEdge[i] = false;
+ ot->m_DelaunayEdge[oi] = false;
+
+ // If triangle have been legalized no need to check the other edges since
+ // the recursive legalization will handles those so we can end here.
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool Sweep::incircle(Point& pa, Point& pb, Point& pc, Point& pd)
+{
+ double adx = pa.m_X - pd.m_X;
+ double ady = pa.m_Y - pd.m_Y;
+ double bdx = pb.m_X - pd.m_X;
+ double bdy = pb.m_Y - pd.m_Y;
+
+ double adxbdy = adx * bdy;
+ double bdxady = bdx * ady;
+ double oabd = adxbdy - bdxady;
+
+ if (oabd <= 0) {
+ return false;
+ }
+
+ double cdx = pc.m_X - pd.m_X;
+ double cdy = pc.m_Y - pd.m_Y;
+
+ double cdxady = cdx * ady;
+ double adxcdy = adx * cdy;
+ double ocad = cdxady - adxcdy;
+
+ if (ocad <= 0) {
+ return false;
+ }
+
+ double bdxcdy = bdx * cdy;
+ double cdxbdy = cdx * bdy;
+
+ double alift = adx * adx + ady * ady;
+ double blift = bdx * bdx + bdy * bdy;
+ double clift = cdx * cdx + cdy * cdy;
+
+ double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;
+
+ return det > 0;
+}
+
+void Sweep::rotateTrianglePair(TriangulationTriangle& t, Point& p,
+ TriangulationTriangle& ot, Point& op)
+{
+ TriangulationTriangle* n1, *n2, *n3, *n4;
+ n1 = t.neighborCCW(p);
+ n2 = t.neighborCW(p);
+ n3 = ot.neighborCCW(op);
+ n4 = ot.neighborCW(op);
+
+ bool ce1, ce2, ce3, ce4;
+ ce1 = t.getConstrainedEdgeCCW(p);
+ ce2 = t.getConstrainedEdgeCW(p);
+ ce3 = ot.getConstrainedEdgeCCW(op);
+ ce4 = ot.getConstrainedEdgeCW(op);
+
+ bool de1, de2, de3, de4;
+ de1 = t.getDelunayEdgeCCW(p);
+ de2 = t.getDelunayEdgeCW(p);
+ de3 = ot.getDelunayEdgeCCW(op);
+ de4 = ot.getDelunayEdgeCW(op);
+
+ t.legalize(p, op);
+ ot.legalize(op, p);
+
+ // Remap delaunay_edge
+ ot.setDelunayEdgeCCW(p, de1);
+ t.setDelunayEdgeCW(p, de2);
+ t.setDelunayEdgeCCW(op, de3);
+ ot.setDelunayEdgeCW(op, de4);
+
+ // Remap constrained_edge
+ ot.setConstrainedEdgeCCW(p, ce1);
+ t.setConstrainedEdgeCW(p, ce2);
+ t.setConstrainedEdgeCCW(op, ce3);
+ ot.setConstrainedEdgeCW(op, ce4);
+
+ // Remap neighbors
+ // XX X: might optimize the markNeighbor by keeping track of
+ // what side should be assigned to what neighbor after the
+ // rotation. Now mark neighbor does lots of testing to find
+ // the right side.
+ t.clearNeighbors();
+ ot.clearNeighbors();
+ if (n1) {
+ ot.markNeighbor(*n1);
+ }
+ if (n2) {
+ t.markNeighbor(*n2);
+ }
+ if (n3) {
+ t.markNeighbor(*n3);
+ }
+ if (n4) {
+ ot.markNeighbor(*n4);
+ }
+ t.markNeighbor(ot);
+}
+
+void Sweep::fillBasin(SweepContext& sc, Node& node)
+{
+ if (orient2d(*node.m_Point, *node.m_Next->m_Point, *node.m_Next->m_Next->m_Point)
+ == CCW) {
+ sc.m_Basin.m_LeftNode = node.m_Next->m_Next;
+ } else {
+ sc.m_Basin.m_LeftNode = node.m_Next;
+ }
+
+ // Find the bottom and right node
+ sc.m_Basin.m_BottomNode = sc.m_Basin.m_LeftNode;
+ while (sc.m_Basin.m_BottomNode->m_Next
+ && sc.m_Basin.m_BottomNode->m_Point->m_Y
+ >= sc.m_Basin.m_BottomNode->m_Next->m_Point->m_Y) {
+ sc.m_Basin.m_BottomNode = sc.m_Basin.m_BottomNode->m_Next;
+ }
+ if (sc.m_Basin.m_BottomNode == sc.m_Basin.m_LeftNode) {
+ // No valid basin
+ return;
+ }
+
+ sc.m_Basin.m_RightNode = sc.m_Basin.m_BottomNode;
+ while (sc.m_Basin.m_RightNode->m_Next
+ && sc.m_Basin.m_RightNode->m_Point->m_Y
+ < sc.m_Basin.m_RightNode->m_Next->m_Point->m_Y) {
+ sc.m_Basin.m_RightNode = sc.m_Basin.m_RightNode->m_Next;
+ }
+ if (sc.m_Basin.m_RightNode == sc.m_Basin.m_BottomNode) {
+ // No valid basins
+ return;
+ }
+
+ sc.m_Basin.m_Width = sc.m_Basin.m_RightNode->m_Point->m_X
+ - sc.m_Basin.m_LeftNode->m_Point->m_X;
+ sc.m_Basin.m_LeftHighest = sc.m_Basin.m_LeftNode->m_Point->m_Y
+ > sc.m_Basin.m_RightNode->m_Point->m_Y;
+
+ fillBasinReq(sc, sc.m_Basin.m_BottomNode);
+}
+
+void Sweep::fillBasinReq(SweepContext& sc, Node* node)
+{
+ // if shallow stop filling
+ if (isShallow(sc, *node)) {
+ return;
+ }
+
+ fill(sc, *node);
+
+ if (node->m_Prev == sc.m_Basin.m_LeftNode
+ && node->m_Next == sc.m_Basin.m_RightNode) {
+ return;
+ } else if (node->m_Prev == sc.m_Basin.m_LeftNode) {
+ Orientation o = orient2d(*node->m_Point, *node->m_Next->m_Point,
+ *node->m_Next->m_Next->m_Point);
+ if (o == CW) {
+ return;
+ }
+ node = node->m_Next;
+ } else if (node->m_Next == sc.m_Basin.m_RightNode) {
+ Orientation o = orient2d(*node->m_Point, *node->m_Prev->m_Point,
+ *node->m_Prev->m_Prev->m_Point);
+ if (o == CCW) {
+ return;
+ }
+ node = node->m_Prev;
+ } else {
+ // Continue with the neighbor node with lowest Y value
+ if (node->m_Prev->m_Point->m_Y < node->m_Next->m_Point->m_Y) {
+ node = node->m_Prev;
+ } else {
+ node = node->m_Next;
+ }
+ }
+
+ fillBasinReq(sc, node);
+}
+
+bool Sweep::isShallow(SweepContext& sc, Node& node)
+{
+ double height;
+
+ if (sc.m_Basin.m_LeftHighest) {
+ height = sc.m_Basin.m_LeftNode->m_Point->m_Y - node.m_Point->m_Y;
+ } else {
+ height = sc.m_Basin.m_RightNode->m_Point->m_Y - node.m_Point->m_Y;
+ }
+
+ // if shallow stop filling
+ if (sc.m_Basin.m_Width > height) {
+ return true;
+ }
+ return false;
+}
+
+void Sweep::fillEdgeEvent(SweepContext& sc, Edge* edge, Node* node)
+{
+ if (sc.m_EdgeEvent.m_Right) {
+ fillRightAboveEdgeEvent(sc, edge, node);
+ } else {
+ fillLeftAboveEdgeEvent(sc, edge, node);
+ }
+}
+
+void Sweep::fillRightAboveEdgeEvent(SweepContext& sc, Edge* edge, Node* node)
+{
+ while (node->m_Next->m_Point->m_X < edge->m_P->m_X) {
+ // Check if next node is below the edge
+ if (orient2d(*edge->m_Q, *node->m_Next->m_Point, *edge->m_P) == CCW) {
+ fillRightBelowEdgeEvent(sc, edge, *node);
+ } else {
+ node = node->m_Next;
+ }
+ }
+}
+
+void Sweep::fillRightBelowEdgeEvent(SweepContext& sc, Edge* edge, Node& node)
+{
+ if (node.m_Point->m_X < edge->m_P->m_X) {
+ if (orient2d(*node.m_Point, *node.m_Next->m_Point, *node.m_Next->m_Next->m_Point)
+ == CCW) {
+ // Concave
+ fillRightConcaveEdgeEvent(sc, edge, node);
+ } else {
+ // Convex
+ fillRightConvexEdgeEvent(sc, edge, node);
+ // Retry this one
+ fillRightBelowEdgeEvent(sc, edge, node);
+ }
+ }
+}
+
+void Sweep::fillRightConcaveEdgeEvent(SweepContext& sc, Edge* edge, Node& node)
+{
+ fill(sc, *node.m_Next);
+ if (node.m_Next->m_Point != edge->m_P) {
+ // Next above or below edge?
+ if (orient2d(*edge->m_Q, *node.m_Next->m_Point, *edge->m_P) == CCW) {
+ // Below
+ if (orient2d(*node.m_Point, *node.m_Next->m_Point,
+ *node.m_Next->m_Next->m_Point) == CCW) {
+ // Next is concave
+ fillRightConcaveEdgeEvent(sc, edge, node);
+ } else {
+ // Next is convex
+ }
+ }
+ }
+
+}
+
+void Sweep::fillRightConvexEdgeEvent(SweepContext& sc, Edge* edge, Node& node)
+{
+ // Next concave or convex?
+ if (orient2d(*node.m_Next->m_Point, *node.m_Next->m_Next->m_Point,
+ *node.m_Next->m_Next->m_Next->m_Point) == CCW) {
+ // Concave
+ fillRightConcaveEdgeEvent(sc, edge, *node.m_Next);
+ } else {
+ // Convex
+ // Next above or below edge?
+ if (orient2d(*edge->m_Q, *node.m_Next->m_Next->m_Point, *edge->m_P) == CCW) {
+ // Below
+ fillRightConvexEdgeEvent(sc, edge, *node.m_Next);
+ } else {
+ // Above
+ }
+ }
+}
+
+void Sweep::fillLeftAboveEdgeEvent(SweepContext& sc, Edge* edge, Node* node)
+{
+ while (node->m_Prev->m_Point->m_X > edge->m_P->m_X) {
+ // Check if next node is below the edge
+ if (orient2d(*edge->m_Q, *node->m_Prev->m_Point, *edge->m_P) == CW) {
+ fillLeftBelowEdgeEvent(sc, edge, *node);
+ } else {
+ node = node->m_Prev;
+ }
+ }
+}
+
+void Sweep::fillLeftBelowEdgeEvent(SweepContext& sc, Edge* edge, Node& node)
+{
+ if (node.m_Point->m_X > edge->m_P->m_X) {
+ if (orient2d(*node.m_Point, *node.m_Prev->m_Point, *node.m_Prev->m_Prev->m_Point)
+ == CW) {
+ // Concave
+ fillLeftConcaveEdgeEvent(sc, edge, node);
+ } else {
+ // Convex
+ fillLeftConvexEdgeEvent(sc, edge, node);
+ // Retry this one
+ fillLeftBelowEdgeEvent(sc, edge, node);
+ }
+ }
+}
+
+void Sweep::fillLeftConvexEdgeEvent(SweepContext& sc, Edge* edge, Node& node)
+{
+ // Next concave or convex?
+ if (orient2d(*node.m_Prev->m_Point, *node.m_Prev->m_Prev->m_Point,
+ *node.m_Prev->m_Prev->m_Prev->m_Point) == CW) {
+ // Concave
+ fillLeftConcaveEdgeEvent(sc, edge, *node.m_Prev);
+ } else {
+ // Convex
+ // Next above or below edge?
+ if (orient2d(*edge->m_Q, *node.m_Prev->m_Prev->m_Point, *edge->m_P) == CW) {
+ // Below
+ fillLeftConvexEdgeEvent(sc, edge, *node.m_Prev);
+ } else {
+ // Above
+ }
+ }
+}
+
+void Sweep::fillLeftConcaveEdgeEvent(SweepContext& sc, Edge* edge, Node& node)
+{
+ fill(sc, *node.m_Prev);
+ if (node.m_Prev->m_Point != edge->m_P) {
+ // Next above or below edge?
+ if (orient2d(*edge->m_Q, *node.m_Prev->m_Point, *edge->m_P) == CW) {
+ // Below
+ if (orient2d(*node.m_Point, *node.m_Prev->m_Point,
+ *node.m_Prev->m_Prev->m_Point) == CW) {
+ // Next is concave
+ fillLeftConcaveEdgeEvent(sc, edge, node);
+ } else {
+ // Next is convex
+ }
+ }
+ }
+
+}
+
+void Sweep::flipEdgeEvent(SweepContext& sc, Point& ep, Point& eq,
+ TriangulationTriangle* t, Point& p)
+{
+ TriangulationTriangle& ot = t->neighborAcross(p);
+ Point& op = *ot.oppositePoint(*t, p);
+
+ if (&ot == NULL) {
+ // If we want to integrate the fillEdgeEvent do it here
+ // With current implementation we should never get here
+ //throw new RuntimeException( "[BUG:FIXM E] FLIP failed due to missing triangle");
+ assert(0);
+ }
+
+ if (inScanArea(p, *t->pointCCW(p), *t->pointCW(p), op)) {
+ // Lets rotate shared edge one vertex CW
+ rotateTrianglePair(*t, p, ot, op);
+ sc.mapTriangleToNodes(*t);
+ sc.mapTriangleToNodes(ot);
+
+ if (p == eq && op == ep) {
+ if (eq == *sc.m_EdgeEvent.m_ConstrainedEdge->m_Q
+ && ep == *sc.m_EdgeEvent.m_ConstrainedEdge->m_P) {
+ t->markConstrainedEdge(&ep, &eq);
+ ot.markConstrainedEdge(&ep, &eq);
+ legalize(sc, *t);
+ legalize(sc, ot);
+ } else {
+ // One of the triangles should be legalized here?
+ }
+ } else {
+ Orientation o = orient2d(eq, op, ep);
+ t = &nextFlipTriangle(sc, (int) o, *t, ot, p, op);
+ flipEdgeEvent(sc, ep, eq, t, p);
+ }
+ } else {
+ Point& newP = nextFlipPoint(ep, eq, ot, op);
+ flipScanEdgeEvent(sc, ep, eq, *t, ot, newP);
+ edgeEvent(sc, ep, eq, t, p);
+ }
+}
+
+TriangulationTriangle& Sweep::nextFlipTriangle(SweepContext& sc, int o,
+ TriangulationTriangle& t, TriangulationTriangle& ot, Point& p, Point& op)
+{
+ if (o == CCW) {
+ // ot is not crossing edge after flip
+ int edgeIndex = ot.edgeIndex(&p, &op);
+ ot.m_DelaunayEdge[edgeIndex] = true;
+ legalize(sc, ot);
+ ot.clearDelunayEdges();
+ return t;
+ }
+
+ // t is not crossing edge after flip
+ int edgeIndex = t.edgeIndex(&p, &op);
+
+ t.m_DelaunayEdge[edgeIndex] = true;
+ legalize(sc, t);
+ t.clearDelunayEdges();
+ return ot;
+}
+
+Point& Sweep::nextFlipPoint(Point& ep, Point& eq, TriangulationTriangle& ot, Point& op)
+{
+ Orientation o2d = orient2d(eq, op, ep);
+ if (o2d == CW) {
+ // Right
+ return *ot.pointCCW(op);
+ } else if (o2d == CCW) {
+ // Left
+ return *ot.pointCW(op);
+ } else {
+ //throw new RuntimeException("[Unsupported] Opposing point on constrained edge");
+ assert(0);
+ return ep; // Silence compiler warning.
+ }
+}
+
+void Sweep::flipScanEdgeEvent(SweepContext& sc, Point& ep, Point& eq,
+ TriangulationTriangle& flipTriangle, TriangulationTriangle& t, Point& p)
+{
+ TriangulationTriangle& ot = t.neighborAcross(p);
+ Point& op = *ot.oppositePoint(t, p);
+
+ if (&t.neighborAcross(p) == NULL) {
+ // If we want to integrate the fillEdgeEvent do it here
+ // With current implementation we should never get here
+ //throw new RuntimeException( "[BUG:FIXM E] FLIP failed due to missing triangle");
+ assert(0);
+ }
+
+ if (inScanArea(eq, *flipTriangle.pointCCW(eq), *flipTriangle.pointCW(eq),
+ op)) {
+ // flip with new edge op->eq
+ flipEdgeEvent(sc, eq, op, &ot, op);
+ // To do: Actually I just figured out that it should be possible to
+ // improve this by getting the next ot and op before the the above
+ // flip and continue the flipScanEdgeEvent here
+ // set new ot and op here and loop back to inScanArea test
+ // also need to set a new flip_triangle first
+ // Turns out at first glance that this is somewhat complicated
+ // so it will have to wait.
+ } else {
+ Point& newP = nextFlipPoint(ep, eq, ot, op);
+ flipScanEdgeEvent(sc, ep, eq, flipTriangle, ot, newP);
+ }
+}
+
+Sweep::~Sweep()
+{
+ for (unsigned int i = 0; i < m_Nodes.size(); i++) {
+ delete m_Nodes[i];
+ }
+
+}
+
+}
diff --git a/src/base/triangulate/Sweep.h b/src/base/triangulate/Sweep.h new file mode 100644 index 0000000..48cd13a --- /dev/null +++ b/src/base/triangulate/Sweep.h @@ -0,0 +1,201 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +// +// Based on Poly2Tri algorithm. +// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors +// http://code.google.com/p/poly2tri/ +// + +#ifndef SWEEP_H +#define SWEEP_H + +#include <vector> + +namespace avg { + +class SweepContext; +struct Node; +struct Point; +struct Edge; +class TriangulationTriangle; + +class Sweep +{ + +public: + + void Triangulate(SweepContext& sc); + + ~Sweep(); + +private: + + void sweepPoints(SweepContext& sc); + + Node& pointEvent(SweepContext& sc, Point& point); + + void edgeEvent(SweepContext& sc, Edge* edge, Node* node); + + void edgeEvent(SweepContext& sc, Point& ep, Point& eq, + TriangulationTriangle* triangle, Point& point); + + Node& newFrontTriangle(SweepContext& sc, Point& point, Node& node); + + void fill(SweepContext& sc, Node& node); + + bool legalize(SweepContext& sc, TriangulationTriangle& t); + + /** + * <b>Requirement</b>:<br> + * 1. a,b and c form a triangle.<br> + * 2. a and d is know to be on opposite side of bc<br> + * <pre> + * a + * + + * / \ + * / \ + * b/ \c + * +-------+ + * / d \ + * / \ + * </pre> + * <b>Fact</b>: d has to be in area B to have a chance to be inside the circle formed by + * a,b and c<br> + * d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW<br> + * This preknowledge gives us a way to optimize the incircle test + * @param a - triangle point, opposite d + * @param b - triangle point + * @param c - triangle point + * @param d - point opposite a + * @return true if d is inside circle, false if on circle edge + */ + bool incircle(Point& pa, Point& pb, Point& pc, Point& pd); + + /** + * Rotates a triangle pair one vertex CW + *<pre> + * n2 n2 + * P +-----+ P +-----+ + * | t /| |\ t | + * | / | | \ | + * n1| / |n3 n1| \ |n3 + * | / | after CW | \ | + * |/ oT | | oT \| + * +-----+ oP +-----+ + * n4 n4 + * </pre> + */ + void rotateTrianglePair(TriangulationTriangle& t, Point& p, TriangulationTriangle& ot, + Point& op); + + void fillAdvancingFront(SweepContext& sc, Node& n); + + double holeAngle(Node& node); + + /** + * The basin angle is decided against the horizontal line [1,0] + */ + double basinAngle(Node& node); + + void fillBasin(SweepContext& sc, Node& node); + + void fillBasinReq(SweepContext& sc, Node* node); + + bool isShallow(SweepContext& sc, Node& node); + + bool isEdgeSideOfTriangle(TriangulationTriangle& triangle, Point& ep, Point& eq); + + void fillEdgeEvent(SweepContext& sc, Edge* edge, Node* node); + + void fillRightAboveEdgeEvent(SweepContext& sc, Edge* edge, Node* node); + + void fillRightBelowEdgeEvent(SweepContext& sc, Edge* edge, Node& node); + + void fillRightConcaveEdgeEvent(SweepContext& sc, Edge* edge, Node& node); + + void fillRightConvexEdgeEvent(SweepContext& sc, Edge* edge, Node& node); + + void fillLeftAboveEdgeEvent(SweepContext& sc, Edge* edge, Node* node); + + void fillLeftBelowEdgeEvent(SweepContext& sc, Edge* edge, Node& node); + + void fillLeftConcaveEdgeEvent(SweepContext& sc, Edge* edge, Node& node); + + void fillLeftConvexEdgeEvent(SweepContext& sc, Edge* edge, Node& node); + + void flipEdgeEvent(SweepContext& sc, Point& ep, Point& eq, TriangulationTriangle* t, + Point& p); + + /** + * After a flip we have two triangles and know that only one will still be + * intersecting the edge. So decide which to contiune with and legalize the other + * + * @param sc + * @param o - should be the result of an orient2d( eq, op, ep ) + * @param t - triangle 1 + * @param ot - triangle 2 + * @param p - a point shared by both triangles + * @param op - another point shared by both triangles + * @return returns the triangle still intersecting the edge + */ + TriangulationTriangle& nextFlipTriangle(SweepContext& sc, int o, + TriangulationTriangle& t, TriangulationTriangle& ot, Point& p, Point& op); + + /** + * When we need to traverse from one triangle to the next we need + * the point in current triangle that is the opposite point to the next + * triangle. + * + * @param ep + * @param eq + * @param ot + * @param op + * @return + */ + Point& nextFlipPoint(Point& ep, Point& eq, TriangulationTriangle& ot, Point& op); + + /** + * Scan part of the FlipScan algorithm<br> + * When a triangle pair isn't flippable we will scan for the next + * point that is inside the flip triangle scan area. When found + * we generate a new flipEdgeEvent + * + * @param sc + * @param ep - last point on the edge we are traversing + * @param eq - first point on the edge we are traversing + * @param flipTriangle - the current triangle sharing the point eq with edge + * @param t + * @param p + */ + void flipScanEdgeEvent(SweepContext& sc, Point& ep, Point& eq, + TriangulationTriangle& flip_triangle, TriangulationTriangle& t, Point& p); + + void finalizationPolygon(SweepContext& sc); + + std::vector<Node*> m_Nodes; + unsigned int arrayCount; + +}; + +} + +#endif diff --git a/src/base/triangulate/SweepContext.cpp b/src/base/triangulate/SweepContext.cpp new file mode 100644 index 0000000..16e642e --- /dev/null +++ b/src/base/triangulate/SweepContext.cpp @@ -0,0 +1,196 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +// +// Based on Poly2Tri algorithm. +// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors +// http://code.google.com/p/poly2tri/ +// + +#include "SweepContext.h" +#include <algorithm> +#include "AdvancingFront.h" + +namespace avg { + +SweepContext::SweepContext(std::vector<Point*> polyline) +{ + m_Basin = Basin(); + m_EdgeEvent = EdgeEvent(); + + m_Points = polyline; + + initEdges(m_Points); +} + +void SweepContext::addHole(std::vector<Point*> polyline) +{ + initEdges(polyline); + for (unsigned int i = 0; i < polyline.size(); i++) { + m_Points.push_back(polyline[i]); + } +} + +void SweepContext::addPoint(Point* point) +{ + m_Points.push_back(point); +} + +std::vector<TriangulationTriangle*>& SweepContext::getTriangles() +{ + return m_Triangles; +} + +void SweepContext::initTriangulation() +{ + double xmax(m_Points[0]->m_X), xmin(m_Points[0]->m_X); + double ymax(m_Points[0]->m_Y), ymin(m_Points[0]->m_Y); + + // Calculate bounds. + for (unsigned int i = 0; i < m_Points.size(); i++) { + Point& p = *m_Points[i]; + if (p.m_X > xmax) { + xmax = p.m_X; + } + if (p.m_X < xmin) { + xmin = p.m_X; + } + if (p.m_Y > ymax) { + ymax = p.m_Y; + } + if (p.m_Y < ymin) { + ymin = p.m_Y; + } + } + + double dx = kAlpha * (xmax - xmin); + double dy = kAlpha * (ymax - ymin); + m_Head = new Point(xmax + dx, ymin - dy, 0); + m_Tail = new Point(xmin - dx, ymin - dy, 0); + + // Sort along y-axis + std::sort(m_Points.begin(), m_Points.end(), cmp); + +} + +void SweepContext::initEdges(std::vector<Point*> polyline) +{ + int numPoints = polyline.size(); + for (int i = 0; i < numPoints; i++) { + int j = i < numPoints - 1 ? i + 1 : 0; + + m_EdgeList.push_back(new Edge(*polyline[i], *polyline[j])); + } +} + +Point* SweepContext::getPoint(const int& index) +{ + return m_Points[index]; +} + +void SweepContext::addToMap(TriangulationTriangle* triangle) +{ + m_Map.push_back(triangle); +} + +Node& SweepContext::locateNode(Point& point) +{ + // TO DO implement search tree + return *m_Front->locateNode(point.m_X); +} + +void SweepContext::createAdvancingFront() +{ + // Initial triangle + TriangulationTriangle* triangle = new TriangulationTriangle(*m_Points[0], *m_Tail, + *m_Head); + + m_Map.push_back(triangle); + + m_AfHead = new Node(*triangle->getPoint(1), *triangle); + m_AfMiddle = new Node(*triangle->getPoint(0), *triangle); + m_AfTail = new Node(*triangle->getPoint(2)); + m_Front = new AdvancingFront(*m_AfHead, *m_AfTail); + + m_AfHead->m_Next = m_AfMiddle; + m_AfMiddle->m_Next = m_AfTail; + m_AfMiddle->m_Prev = m_AfHead; + m_AfTail->m_Prev = m_AfMiddle; +} + +void SweepContext::removeNode(Node* node) +{ + delete node; +} + +void SweepContext::mapTriangleToNodes(TriangulationTriangle& t) +{ + for (int i = 0; i < 3; i++) { + if (!t.getNeighbor(i)) { + Node* n = m_Front->locatePoint(t.pointCW(*t.getPoint(i))); + if (n) { + n->m_Triangle = &t; + } + } + } +} + +void SweepContext::removeFromMap(TriangulationTriangle* triangle) +{ + m_Map.remove(triangle); +} + +void SweepContext::meshClean(TriangulationTriangle& triangle) +{ + if (&triangle != NULL && !triangle.isInterior()) { + triangle.isInterior(true); + m_Triangles.push_back(&triangle); + for (int i = 0; i < 3; i++) { + if (!triangle.m_ConstrainedEdge[i]) + meshClean(*triangle.getNeighbor(i)); + } + } +} + +SweepContext::~SweepContext() +{ + + delete m_Head; + delete m_Tail; + delete m_Front; + delete m_AfHead; + delete m_AfMiddle; + delete m_AfTail; + + typedef std::list<TriangulationTriangle*> type_list; + + for (type_list::iterator iter = m_Map.begin(); iter != m_Map.end(); ++iter) { + TriangulationTriangle* ptr = *iter; + delete ptr; + } + + for (unsigned int i = 0; i < m_EdgeList.size(); i++) { + delete m_EdgeList[i]; + } + +} + +} diff --git a/src/base/triangulate/SweepContext.h b/src/base/triangulate/SweepContext.h new file mode 100644 index 0000000..0b9e51d --- /dev/null +++ b/src/base/triangulate/SweepContext.h @@ -0,0 +1,181 @@ +//
+// libavg - Media Playback Engine.
+// Copyright (C) 2003-2014 Ulrich von Zadow +//
+// 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 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Current versions can be found at www.libavg.de
+//
+
+//
+// Based on Poly2Tri algorithm.
+// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+// http://code.google.com/p/poly2tri/
+//
+
+#ifndef SWEEP_CONTEXT_H
+#define SWEEP_CONTEXT_H
+
+#include <list>
+#include <vector>
+#include <cstddef>
+
+namespace avg {
+
+// Inital triangle factor, seed triangle will extend 30% of
+// PointSet width to both left and right.
+const double kAlpha = 0.3;
+
+struct Point;
+class TriangulationTriangle;
+struct Node;
+struct Edge;
+class AdvancingFront;
+
+class SweepContext
+{
+
+public:
+
+ SweepContext(std::vector<Point*> polyline);
+
+ ~SweepContext();
+
+ void setHead(Point* p1);
+
+ Point* head();
+
+ void setTail(Point* p1);
+
+ Point* tail();
+
+ int pointCount();
+
+ Node& locateNode(Point& point);
+
+ void removeNode(Node* node);
+
+ void createAdvancingFront();
+
+/// Try to map a node to all sides of this triangle that don't have a neighbor
+ void mapTriangleToNodes(TriangulationTriangle& t);
+
+ void addToMap(TriangulationTriangle* triangle);
+
+ Point* getPoint(const int& index);
+
+ Point* GetPoints();
+
+ void removeFromMap(TriangulationTriangle* triangle);
+
+ void addHole(std::vector<Point*> polyline);
+
+ void addPoint(Point* point);
+
+ AdvancingFront* front();
+
+ void meshClean(TriangulationTriangle& triangle);
+
+ std::vector<TriangulationTriangle*>& getTriangles();
+
+ std::vector<Edge*> m_EdgeList;
+
+ struct Basin
+ {
+ Node* m_LeftNode;
+ Node* m_BottomNode;
+ Node* m_RightNode;
+ double m_Width;
+ bool m_LeftHighest;
+
+ Basin()
+ {
+ clear();
+ }
+
+ void clear() {
+ m_LeftNode = NULL;
+ m_BottomNode = NULL;
+ m_RightNode = NULL;
+ m_Width = 0.0;
+ m_LeftHighest = false;
+ }
+ };
+
+ struct EdgeEvent
+ {
+ Edge* m_ConstrainedEdge;
+ bool m_Right;
+
+ EdgeEvent() :
+ m_ConstrainedEdge(NULL), m_Right(false) {
+ }
+ };
+
+ Basin m_Basin;
+ EdgeEvent m_EdgeEvent;
+
+private:
+
+ friend class Sweep;
+
+ std::vector<TriangulationTriangle*> m_Triangles;
+ std::list<TriangulationTriangle*> m_Map;
+ std::vector<Point*> m_Points;
+
+ AdvancingFront* m_Front;
+ Point* m_Head;
+ Point* m_Tail;
+
+ Node *m_AfHead, *m_AfMiddle, *m_AfTail;
+
+ void initTriangulation();
+ void initEdges(std::vector<Point*> polyline);
+
+};
+
+inline AdvancingFront* SweepContext::front()
+{
+ return m_Front;
+}
+
+inline int SweepContext::pointCount()
+{
+ return m_Points.size();
+}
+
+inline void SweepContext::setHead(Point* p1)
+{
+ m_Head = p1;
+}
+
+inline Point* SweepContext::head()
+{
+ return m_Head;
+}
+
+inline void SweepContext::setTail(Point* p1)
+{
+ m_Tail = p1;
+}
+
+inline Point* SweepContext::tail()
+{
+ return m_Tail;
+}
+
+}
+
+#endif
diff --git a/src/base/triangulate/Triangulate.cpp b/src/base/triangulate/Triangulate.cpp new file mode 100644 index 0000000..9206327 --- /dev/null +++ b/src/base/triangulate/Triangulate.cpp @@ -0,0 +1,90 @@ +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +// +// Based on Poly2Tri algorithm. +// Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors +// http://code.google.com/p/poly2tri/ +// + +#include "Triangulate.h" +#include "Sweep.h" +#include "SweepContext.h" + +#include "Shapes.h" + +using namespace std; + +namespace avg { + +void triangulatePolygon(std::vector<unsigned int>& dest, const Vec2Vector& points, + const std::vector<unsigned int>& holeIndexes) +{ + std::vector<Point*> polyline; + std::vector<Point*> holeLine; + unsigned int contourEnd; + + if (holeIndexes.size() > 0) { + contourEnd = holeIndexes[0]; + } else { + contourEnd = points.size(); + } + + for (unsigned int i = 0; i < contourEnd; i++) { + polyline.push_back(new Point(points[i].x, points[i].y, i)); + } + + SweepContext* sweepContext = new SweepContext(polyline); + Sweep* sweep = new Sweep; + + if (holeIndexes.size() > 0) { + for (unsigned int i = 0; i < holeIndexes.size(); i++) { + if ( i < holeIndexes.size()-1) { + for (unsigned int j = holeIndexes[i]; j < points.size() && j < + holeIndexes[i+1]; j++) + { + holeLine.push_back(new Point(points[j].x, points[j].y, j)); + } + } else { + for (unsigned int j = holeIndexes[i]; j < points.size(); j++) { + holeLine.push_back(new Point(points[j].x, points[j].y, j)); + } + } + sweepContext->addHole(holeLine); + holeLine.clear(); + } + } + + sweep->Triangulate(*sweepContext); + + std::vector<avg::TriangulationTriangle*>& triangles = sweepContext->getTriangles(); + for (unsigned int i = 0; i < triangles.size(); ++i) { + dest.push_back(triangles[i]->getPoint(0)->m_Index); + dest.push_back(triangles[i]->getPoint(1)->m_Index); + dest.push_back(triangles[i]->getPoint(2)->m_Index); + } + + delete sweep; + delete sweepContext; + + for (unsigned int i = 0; i < polyline.size(); i++) { + delete polyline[i]; + } +} + +} diff --git a/src/base/triangulate/Triangulate.h b/src/base/triangulate/Triangulate.h new file mode 100644 index 0000000..af538a6 --- /dev/null +++ b/src/base/triangulate/Triangulate.h @@ -0,0 +1,33 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// 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 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#ifndef TRIANGULATION_H_ +#define TRIANGULATION_H_ + +#include "../GLMHelper.h" +namespace avg { + + void triangulatePolygon(std::vector<unsigned int>& dest, const Vec2Vector& points, + const std::vector<unsigned int>& holeIndexes = std::vector<unsigned int>()); + +} + +#endif /* TRIANGULATION_H_ */ diff --git a/src/base/triangulate/Utils.h b/src/base/triangulate/Utils.h new file mode 100644 index 0000000..5dd6685 --- /dev/null +++ b/src/base/triangulate/Utils.h @@ -0,0 +1,124 @@ +/*
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UTILS_H
+#define UTILS_H
+
+// Otherwise #defines like M_PI are undeclared under Visual Studio
+#define _USE_MATH_DEFINES
+
+#include <exception>
+#include <math.h>
+
+namespace avg {
+
+const double PI_3div4 = 3 * M_PI / 4;
+const double EPSILON = 1e-12;
+
+enum Orientation
+{
+ CW, CCW, COLLINEAR
+};
+
+/**
+ * Forumla to calculate signed area<br>
+ * Positive if CCW<br>
+ * Negative if CW<br>
+ * 0 if collinear<br>
+ * <pre>
+ * A[P1,P2,P3] = (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
+ * = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
+ * </pre>
+ */
+Orientation orient2d(Point& pa, Point& pb, Point& pc)
+{
+ double detleft = (pa.m_X - pc.m_X) * (pb.m_Y - pc.m_Y);
+ double detright = (pa.m_Y - pc.m_Y) * (pb.m_X - pc.m_X);
+ double val = detleft - detright;
+ if (val > -EPSILON && val < EPSILON) {
+ return COLLINEAR;
+ } else if (val > 0) {
+ return CCW;
+ }
+ return CW;
+}
+
+/*
+ bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd)
+ {
+ double pdx = pd.x;
+ double pdy = pd.y;
+ double adx = pa.x - pdx;
+ double ady = pa.y - pdy;
+ double bdx = pb.x - pdx;
+ double bdy = pb.y - pdy;
+
+ double adxbdy = adx * bdy;
+ double bdxady = bdx * ady;
+ double oabd = adxbdy - bdxady;
+
+ if (oabd <= EPSILON) {
+ return false;
+ }
+
+ double cdx = pc.x - pdx;
+ double cdy = pc.y - pdy;
+
+ double cdxady = cdx * ady;
+ double adxcdy = adx * cdy;
+ double ocad = cdxady - adxcdy;
+
+ if (ocad <= EPSILON) {
+ return false;
+ }
+
+ return true;
+ }
+
+ */
+
+bool inScanArea(Point& pa, Point& pb, Point& pc, Point& pd)
+{
+ double oadb = (pa.m_X - pb.m_X) * (pd.m_Y - pb.m_Y) - (pd.m_X - pb.m_X) * (pa.m_Y - pb.m_Y);
+ if (oadb >= -EPSILON) {
+ return false;
+ }
+
+ double oadc = (pa.m_X - pc.m_X) * (pd.m_Y - pc.m_Y) - (pd.m_X - pc.m_X) * (pa.m_Y - pc.m_Y);
+ if (oadc <= EPSILON) {
+ return false;
+ }
+ return true;
+}
+
+}
+
+#endif
|