<commit_before>/***************************************************************************
 *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library 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 Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#endif

#include "PropertyPythonObject.h"
#include "DocumentObjectPy.h"
#include "DocumentObject.h"
#include <Base/Base64.h>
#include <Base/Writer.h>
#include <Base/Reader.h>
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <iostream>
#include <boost/regex.hpp>

using namespace App;

TYPESYSTEM_SOURCE(App::PropertyPythonObject , App::Property);

PropertyPythonObject::PropertyPythonObject()
{
}

PropertyPythonObject::~PropertyPythonObject()
{
    // this is needed because the release of the pickled object may need the
    // GIL. Thus, we grab the GIL and replace the pickled with an empty object
    Base::PyGILStateLocker lock;
    this->object = Py::Object();
}

void PropertyPythonObject::setValue(Py::Object o)
{
    Base::PyGILStateLocker lock;
    aboutToSetValue();
    this->object = o;
    hasSetValue();
}

Py::Object PropertyPythonObject::getValue() const
{
    return object;
}

PyObject *PropertyPythonObject::getPyObject(void)
{
    return Py::new_reference_to(this->object);
}

void PropertyPythonObject::setPyObject(PyObject * obj)
{
    Base::PyGILStateLocker lock;
    aboutToSetValue();
    this->object = obj;
    hasSetValue();
}

std::string PropertyPythonObject::toString() const
{
    std::string repr;
    Base::PyGILStateLocker lock;
    try {
        Py::Module pickle(PyImport_ImportModule("json"),true);
        if (pickle.isNull())
            throw Py::Exception();
        Py::Callable method(pickle.getAttr(std::string("dumps")));
        Py::Object dump;
        if (this->object.hasAttr("__getstate__")) {
            Py::Tuple args;
            Py::Callable state(this->object.getAttr("__getstate__"));
            dump = state.apply(args);
        }
        else if (this->object.hasAttr("__dict__")) {
            dump = this->object.getAttr("__dict__");
        }
        else {
            dump = this->object;
        }

        Py::Tuple args(1);
        args.setItem(0, dump);
        Py::Object res = method.apply(args);
        Py::String str(res);
        repr = str.as_std_string("ascii");
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        e.ReportException();
    }

    return repr;
}

void PropertyPythonObject::fromString(const std::string& repr)
{
    Base::PyGILStateLocker lock;
    try {
        if (repr.empty())
            return;
        Py::Module pickle(PyImport_ImportModule("json"),true);
        if (pickle.isNull())
            throw Py::Exception();
        Py::Callable method(pickle.getAttr(std::string("loads")));
        Py::Tuple args(1);
        args.setItem(0, Py::String(repr));
        Py::Object res = method.apply(args);

        if (this->object.hasAttr("__setstate__")) {
            Py::Tuple args(1);
            args.setItem(0, res);
            Py::Callable state(this->object.getAttr("__setstate__"));
            state.apply(args);
        }
        else if (this->object.hasAttr("__dict__")) {
            this->object.setAttr("__dict__", res);
        }
        else {
            this->object = res;
        }
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        e.ReportException();
    }
}

void PropertyPythonObject::loadPickle(const std::string& str)
{
    // find the custom attributes and restore them
    Base::PyGILStateLocker lock;
    try {
        std::string buffer = str;
        boost::regex pickle("S'(\\w+)'.+S'(\\w+)'\\n");
        boost::match_results<std::string::const_iterator> what;
        std::string::const_iterator start, end;
        start = buffer.begin();
        end = buffer.end();
        while (boost::regex_search(start, end, what, pickle)) {
            std::string key = std::string(what[1].first, what[1].second);
            std::string val = std::string(what[2].first, what[2].second);
            this->object.setAttr(key, Py::String(val));
            buffer = std::string(what[2].second, end);
            start = buffer.begin();
            end = buffer.end();
        }
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        e.ReportException();
    }
}

std::string PropertyPythonObject::encodeValue(const std::string& str) const
{
    std::string tmp;
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
        if (*it == '<')
            tmp += "<";
        else if (*it == '"')
            tmp += """;
        else if (*it == '&')
            tmp += "&";
        else if (*it == '>')
            tmp += "&gt";
        else if (*it == '\n')
            tmp += "\\n";
        else
            tmp += *it;
    }

    return tmp;
}

std::string PropertyPythonObject::decodeValue(const std::string& str) const
{
    std::string tmp;
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
        if (*it == '\\') {
            ++it;
            if (it != str.end() && *it == 'n') {
                tmp += '\n';
            }
        }
        else
            tmp += *it;
    }

    return tmp;
}

void PropertyPythonObject::saveObject(Base::Writer &writer) const
{
    Base::PyGILStateLocker lock;
    try {
        PropertyContainer* parent = this->getContainer();
        if (parent->isDerivedFrom(Base::Type::fromName("App::DocumentObject"))) {
            if (this->object.hasAttr("__object__")) {
                writer.Stream() << " object=\"yes\"";
            }
        }
        if (parent->isDerivedFrom(Base::Type::fromName("Gui::ViewProvider"))) {
            if (this->object.hasAttr("__vobject__")) {
                writer.Stream() << " vobject=\"yes\"";
            }
        }
    }
    catch (Py::Exception& e) {
        e.clear();
    }
}

void PropertyPythonObject::restoreObject(Base::XMLReader &reader)
{
    Base::PyGILStateLocker lock;
    try {
        PropertyContainer* parent = this->getContainer();
        if (reader.hasAttribute("object")) {
            if (strcmp(reader.getAttribute("object"),"yes") == 0) {
                Py::Object obj = Py::asObject(parent->getPyObject());
                this->object.setAttr("__object__", obj);
            }
        }
        if (reader.hasAttribute("vobject")) {
            if (strcmp(reader.getAttribute("vobject"),"yes") == 0) {
                Py::Object obj = Py::asObject(parent->getPyObject());
                this->object.setAttr("__vobject__", obj);
            }
        }
    }
    catch (Py::Exception& e) {
        e.clear();
    }
    catch (const Base::Exception& e) {
        Base::Console().Error("%s\n",e.what());
    }
    catch (...) {
        Base::Console().Error("Critical error in PropertyPythonObject::restoreObject\n");
    }
}

void PropertyPythonObject::Save (Base::Writer &writer) const
{
    //if (writer.isForceXML()) {
        std::string repr = this->toString();
        repr = Base::base64_encode((const unsigned char*)repr.c_str(), repr.size());
        std::string val = /*encodeValue*/(repr);
        writer.Stream() << writer.ind() << "<Python value=\"" << val
                        << "\" encoded=\"yes\"";

        Base::PyGILStateLocker lock;
        try {
            if (this->object.hasAttr("__module__") && this->object.hasAttr("__class__")) {
                Py::String mod(this->object.getAttr("__module__"));
                Py::Object cls(this->object.getAttr("__class__"));
                if (cls.hasAttr("__name__")) {
                    Py::String name(cls.getAttr("__name__"));
                    writer.Stream() << " module=\"" << (std::string)mod << "\""
                                    << " class=\"" << (std::string)name << "\"";
                }
            }
            else {
                writer.Stream() << " json=\"yes\"";
            }
        }
        catch (Py::Exception&) {
            Base::PyException e; // extract the Python error text
            e.ReportException();
        }

        saveObject(writer);
        writer.Stream() << "/>" << std::endl;
    //}
    //else {
    //    writer.Stream() << writer.ind() << "<Python file=\"" <<
    //    writer.addFile("pickle", this) << "\"/>" << std::endl;
    //}
}

void PropertyPythonObject::Restore(Base::XMLReader &reader)
{
    reader.readElement("Python");
    if (reader.hasAttribute("file")) {
        std::string file(reader.getAttribute("file"));
        reader.addFile(file.c_str(),this);
    }
    else {
        bool load_json=false;
        bool load_pickle=false;
        bool load_failed=false;
        std::string buffer = reader.getAttribute("value");
        if (reader.hasAttribute("encoded") &&
            strcmp(reader.getAttribute("encoded"),"yes") == 0) {
            buffer = Base::base64_decode(buffer);
        }
        else {
            buffer = decodeValue(buffer);
        }

        Base::PyGILStateLocker lock;
        try {
            boost::regex pickle("^\\(i(\\w+)\\n(\\w+)\\n");
            boost::match_results<std::string::const_iterator> what;
            std::string::const_iterator start, end;
            start = buffer.begin();
            end = buffer.end();
            if (reader.hasAttribute("module") && reader.hasAttribute("class")) {
                Py::Module mod(PyImport_ImportModule(reader.getAttribute("module")),true);
                if (mod.isNull())
                    throw Py::Exception();
                PyObject* cls = mod.getAttr(reader.getAttribute("class")).ptr();
#if PY_MAJOR_VERSION >= 3
                if (PyType_Check(cls)) {
#else
                if (PyClass_Check(cls)) {
                    this->object = PyInstance_NewRaw(cls, 0);
                }
                else if (PyType_Check(cls)) {
#endif
                    this->object = PyType_GenericAlloc((PyTypeObject*)cls, 0);
                }
                else {
                    throw Py::TypeError("neither class nor type object");
                }
                load_json = true;
            }
            else if (boost::regex_search(start, end, what, pickle)) {
                std::string nam = std::string(what[1].first, what[1].second);
                std::string cls = std::string(what[2].first, what[2].second);
                Py::Module mod(PyImport_ImportModule(nam.c_str()),true);
                if (mod.isNull())
                    throw Py::Exception();
#if PY_MAJOR_VERSION >= 3
                this->object = PyObject_CallObject(mod.getAttr(cls).ptr(), NULL);
#else
                this->object = PyInstance_NewRaw(mod.getAttr(cls).ptr(), 0);
#endif
                load_pickle = true;
                buffer = std::string(what[2].second, end);
            }
            else if (reader.hasAttribute("json")) {
                load_json = true;
            }
        }
        catch (Py::Exception&) {
            Base::PyException e; // extract the Python error text
            e.ReportException();
            this->object = Py::None();
            load_failed = true;
        }

        aboutToSetValue();
        if (load_json)
            this->fromString(buffer);
        else if (load_pickle)
            this->loadPickle(buffer);
        else if (!load_failed)
            Base::Console().Warning("PropertyPythonObject::Restore: unsupported serialisation: %s\n", buffer.c_str());
        restoreObject(reader);
        hasSetValue();
    }
}

void PropertyPythonObject::SaveDocFile (Base::Writer &writer) const
{
    std::string buffer = this->toString();
    for (std::string::iterator it = buffer.begin(); it != buffer.end(); ++it)
        writer.Stream().put(*it);
}

void PropertyPythonObject::RestoreDocFile(Base::Reader &reader)
{
    aboutToSetValue();
    std::string buffer;
    char c;
    while (reader.get(c)) {
        buffer.push_back(c);
    }
    this->fromString(buffer);
    hasSetValue();
}

unsigned int PropertyPythonObject::getMemSize (void) const
{
    return sizeof(Py::Object);
}

Property *PropertyPythonObject::Copy(void) const
{
    PropertyPythonObject *p = new PropertyPythonObject();
    Base::PyGILStateLocker lock;
    p->object = this->object;
    return p;
}

void PropertyPythonObject::Paste(const Property &from)
{
    if (from.getTypeId() == PropertyPythonObject::getClassTypeId()) {
        Base::PyGILStateLocker lock;
        aboutToSetValue();
        this->object = static_cast<const PropertyPythonObject&>(from).object;
        hasSetValue();
    }
}
<commit_msg>Py3: fix crash if class is not part of a module any more<commit_after>/***************************************************************************
 *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library 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 Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#endif

#include "PropertyPythonObject.h"
#include "DocumentObjectPy.h"
#include "DocumentObject.h"
#include <Base/Base64.h>
#include <Base/Writer.h>
#include <Base/Reader.h>
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <iostream>
#include <boost/regex.hpp>

using namespace App;

TYPESYSTEM_SOURCE(App::PropertyPythonObject , App::Property);

PropertyPythonObject::PropertyPythonObject()
{
}

PropertyPythonObject::~PropertyPythonObject()
{
    // this is needed because the release of the pickled object may need the
    // GIL. Thus, we grab the GIL and replace the pickled with an empty object
    Base::PyGILStateLocker lock;
    this->object = Py::Object();
}

void PropertyPythonObject::setValue(Py::Object o)
{
    Base::PyGILStateLocker lock;
    aboutToSetValue();
    this->object = o;
    hasSetValue();
}

Py::Object PropertyPythonObject::getValue() const
{
    return object;
}

PyObject *PropertyPythonObject::getPyObject(void)
{
    return Py::new_reference_to(this->object);
}

void PropertyPythonObject::setPyObject(PyObject * obj)
{
    Base::PyGILStateLocker lock;
    aboutToSetValue();
    this->object = obj;
    hasSetValue();
}

std::string PropertyPythonObject::toString() const
{
    std::string repr;
    Base::PyGILStateLocker lock;
    try {
        Py::Module pickle(PyImport_ImportModule("json"),true);
        if (pickle.isNull())
            throw Py::Exception();
        Py::Callable method(pickle.getAttr(std::string("dumps")));
        Py::Object dump;
        if (this->object.hasAttr("__getstate__")) {
            Py::Tuple args;
            Py::Callable state(this->object.getAttr("__getstate__"));
            dump = state.apply(args);
        }
        else if (this->object.hasAttr("__dict__")) {
            dump = this->object.getAttr("__dict__");
        }
        else {
            dump = this->object;
        }

        Py::Tuple args(1);
        args.setItem(0, dump);
        Py::Object res = method.apply(args);
        Py::String str(res);
        repr = str.as_std_string("ascii");
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        e.ReportException();
    }

    return repr;
}

void PropertyPythonObject::fromString(const std::string& repr)
{
    Base::PyGILStateLocker lock;
    try {
        if (repr.empty())
            return;
        Py::Module pickle(PyImport_ImportModule("json"),true);
        if (pickle.isNull())
            throw Py::Exception();
        Py::Callable method(pickle.getAttr(std::string("loads")));
        Py::Tuple args(1);
        args.setItem(0, Py::String(repr));
        Py::Object res = method.apply(args);

        if (this->object.hasAttr("__setstate__")) {
            Py::Tuple args(1);
            args.setItem(0, res);
            Py::Callable state(this->object.getAttr("__setstate__"));
            state.apply(args);
        }
        else if (this->object.hasAttr("__dict__")) {
            this->object.setAttr("__dict__", res);
        }
        else {
            this->object = res;
        }
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        e.ReportException();
    }
}

void PropertyPythonObject::loadPickle(const std::string& str)
{
    // find the custom attributes and restore them
    Base::PyGILStateLocker lock;
    try {
        std::string buffer = str;
        boost::regex pickle("S'(\\w+)'.+S'(\\w+)'\\n");
        boost::match_results<std::string::const_iterator> what;
        std::string::const_iterator start, end;
        start = buffer.begin();
        end = buffer.end();
        while (boost::regex_search(start, end, what, pickle)) {
            std::string key = std::string(what[1].first, what[1].second);
            std::string val = std::string(what[2].first, what[2].second);
            this->object.setAttr(key, Py::String(val));
            buffer = std::string(what[2].second, end);
            start = buffer.begin();
            end = buffer.end();
        }
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        e.ReportException();
    }
}

std::string PropertyPythonObject::encodeValue(const std::string& str) const
{
    std::string tmp;
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
        if (*it == '<')
            tmp += "<";
        else if (*it == '"')
            tmp += """;
        else if (*it == '&')
            tmp += "&";
        else if (*it == '>')
            tmp += "&gt";
        else if (*it == '\n')
            tmp += "\\n";
        else
            tmp += *it;
    }

    return tmp;
}

std::string PropertyPythonObject::decodeValue(const std::string& str) const
{
    std::string tmp;
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
        if (*it == '\\') {
            ++it;
            if (it != str.end() && *it == 'n') {
                tmp += '\n';
            }
        }
        else
            tmp += *it;
    }

    return tmp;
}

void PropertyPythonObject::saveObject(Base::Writer &writer) const
{
    Base::PyGILStateLocker lock;
    try {
        PropertyContainer* parent = this->getContainer();
        if (parent->isDerivedFrom(Base::Type::fromName("App::DocumentObject"))) {
            if (this->object.hasAttr("__object__")) {
                writer.Stream() << " object=\"yes\"";
            }
        }
        if (parent->isDerivedFrom(Base::Type::fromName("Gui::ViewProvider"))) {
            if (this->object.hasAttr("__vobject__")) {
                writer.Stream() << " vobject=\"yes\"";
            }
        }
    }
    catch (Py::Exception& e) {
        e.clear();
    }
}

void PropertyPythonObject::restoreObject(Base::XMLReader &reader)
{
    Base::PyGILStateLocker lock;
    try {
        PropertyContainer* parent = this->getContainer();
        if (reader.hasAttribute("object")) {
            if (strcmp(reader.getAttribute("object"),"yes") == 0) {
                Py::Object obj = Py::asObject(parent->getPyObject());
                this->object.setAttr("__object__", obj);
            }
        }
        if (reader.hasAttribute("vobject")) {
            if (strcmp(reader.getAttribute("vobject"),"yes") == 0) {
                Py::Object obj = Py::asObject(parent->getPyObject());
                this->object.setAttr("__vobject__", obj);
            }
        }
    }
    catch (Py::Exception& e) {
        e.clear();
    }
    catch (const Base::Exception& e) {
        Base::Console().Error("%s\n",e.what());
    }
    catch (...) {
        Base::Console().Error("Critical error in PropertyPythonObject::restoreObject\n");
    }
}

void PropertyPythonObject::Save (Base::Writer &writer) const
{
    //if (writer.isForceXML()) {
        std::string repr = this->toString();
        repr = Base::base64_encode((const unsigned char*)repr.c_str(), repr.size());
        std::string val = /*encodeValue*/(repr);
        writer.Stream() << writer.ind() << "<Python value=\"" << val
                        << "\" encoded=\"yes\"";

        Base::PyGILStateLocker lock;
        try {
            if (this->object.hasAttr("__module__") && this->object.hasAttr("__class__")) {
                Py::String mod(this->object.getAttr("__module__"));
                Py::Object cls(this->object.getAttr("__class__"));
                if (cls.hasAttr("__name__")) {
                    Py::String name(cls.getAttr("__name__"));
                    writer.Stream() << " module=\"" << (std::string)mod << "\""
                                    << " class=\"" << (std::string)name << "\"";
                }
            }
            else {
                writer.Stream() << " json=\"yes\"";
            }
        }
        catch (Py::Exception&) {
            Base::PyException e; // extract the Python error text
            e.ReportException();
        }

        saveObject(writer);
        writer.Stream() << "/>" << std::endl;
    //}
    //else {
    //    writer.Stream() << writer.ind() << "<Python file=\"" <<
    //    writer.addFile("pickle", this) << "\"/>" << std::endl;
    //}
}

void PropertyPythonObject::Restore(Base::XMLReader &reader)
{
    reader.readElement("Python");
    if (reader.hasAttribute("file")) {
        std::string file(reader.getAttribute("file"));
        reader.addFile(file.c_str(),this);
    }
    else {
        bool load_json=false;
        bool load_pickle=false;
        bool load_failed=false;
        std::string buffer = reader.getAttribute("value");
        if (reader.hasAttribute("encoded") &&
            strcmp(reader.getAttribute("encoded"),"yes") == 0) {
            buffer = Base::base64_decode(buffer);
        }
        else {
            buffer = decodeValue(buffer);
        }

        Base::PyGILStateLocker lock;
        try {
            boost::regex pickle("^\\(i(\\w+)\\n(\\w+)\\n");
            boost::match_results<std::string::const_iterator> what;
            std::string::const_iterator start, end;
            start = buffer.begin();
            end = buffer.end();
            if (reader.hasAttribute("module") && reader.hasAttribute("class")) {
                Py::Module mod(PyImport_ImportModule(reader.getAttribute("module")),true);
                if (mod.isNull())
                    throw Py::Exception();
                PyObject* cls = mod.getAttr(reader.getAttribute("class")).ptr();
                if (!cls) {
                    std::stringstream s;
                    s << "Module " << reader.getAttribute("module")
                      << " has no class " << reader.getAttribute("class");
                    throw Py::AttributeError(s.str());
                }
#if PY_MAJOR_VERSION >= 3
                if (PyType_Check(cls)) {
#else
                if (PyClass_Check(cls)) {
                    this->object = PyInstance_NewRaw(cls, 0);
                }
                else if (PyType_Check(cls)) {
#endif
                    this->object = PyType_GenericAlloc((PyTypeObject*)cls, 0);
                }
                else {
                    throw Py::TypeError("neither class nor type object");
                }
                load_json = true;
            }
            else if (boost::regex_search(start, end, what, pickle)) {
                std::string nam = std::string(what[1].first, what[1].second);
                std::string cls = std::string(what[2].first, what[2].second);
                Py::Module mod(PyImport_ImportModule(nam.c_str()),true);
                if (mod.isNull())
                    throw Py::Exception();
#if PY_MAJOR_VERSION >= 3
                this->object = PyObject_CallObject(mod.getAttr(cls).ptr(), NULL);
#else
                this->object = PyInstance_NewRaw(mod.getAttr(cls).ptr(), 0);
#endif
                load_pickle = true;
                buffer = std::string(what[2].second, end);
            }
            else if (reader.hasAttribute("json")) {
                load_json = true;
            }
        }
        catch (Py::Exception&) {
            Base::PyException e; // extract the Python error text
            e.ReportException();
            this->object = Py::None();
            load_failed = true;
        }

        aboutToSetValue();
        if (load_json)
            this->fromString(buffer);
        else if (load_pickle)
            this->loadPickle(buffer);
        else if (!load_failed)
            Base::Console().Warning("PropertyPythonObject::Restore: unsupported serialisation: %s\n", buffer.c_str());
        restoreObject(reader);
        hasSetValue();
    }
}

void PropertyPythonObject::SaveDocFile (Base::Writer &writer) const
{
    std::string buffer = this->toString();
    for (std::string::iterator it = buffer.begin(); it != buffer.end(); ++it)
        writer.Stream().put(*it);
}

void PropertyPythonObject::RestoreDocFile(Base::Reader &reader)
{
    aboutToSetValue();
    std::string buffer;
    char c;
    while (reader.get(c)) {
        buffer.push_back(c);
    }
    this->fromString(buffer);
    hasSetValue();
}

unsigned int PropertyPythonObject::getMemSize (void) const
{
    return sizeof(Py::Object);
}

Property *PropertyPythonObject::Copy(void) const
{
    PropertyPythonObject *p = new PropertyPythonObject();
    Base::PyGILStateLocker lock;
    p->object = this->object;
    return p;
}

void PropertyPythonObject::Paste(const Property &from)
{
    if (from.getTypeId() == PropertyPythonObject::getClassTypeId()) {
        Base::PyGILStateLocker lock;
        aboutToSetValue();
        this->object = static_cast<const PropertyPythonObject&>(from).object;
        hasSetValue();
    }
}
<|endoftext|>


<commit_before>// ========================================================================== //
// This file is part of DO-CV, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2013 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <DO/Sara/Graphics.hpp>

#include "GraphicsUtilities.hpp"

namespace DO { namespace Sara {

  bool load(Image<Color3ub>& I, const std::string& name)
  {
    QImage image(QString(name.c_str()));
    if (image.isNull())
      return false;
    image = image.convertToFormat(QImage::Format_RGB888);
    I.resize(image.width(), image.height());

    Color3ub *dst = I.data();
    Color3ub *src = reinterpret_cast<Color3ub *>(image.bits());
    std::copy(src, src+image.width()*image.height(), dst);
    return true;
  }

  bool load(Image<Rgb8>& image, const std::string& name)
  {
    QImage qimage(QString(name.c_str()));
    if (qimage.isNull())
      return false;
    qimage = qimage.convertToFormat(QImage::Format_RGB32);
    if (qimage.format() != QImage::Format_RGB32)
      throw std::runtime_error("Failed to convert image to format RGB32");
    image.resize(qimage.width(), qimage.height());
    const int *src = reinterpret_cast<const int *>(qimage.constBits());
    for (Rgb8 *dst = image.data(); dst != image.end(); ++dst, ++src)
    {
      (*dst)[0] = *src;
      (*dst)[1] = *src >> 8;
      (*dst)[2] = *src >> 16;
    }
    return true;
  }

  bool load_from_dialog_box(Image<Rgb8>& image)
  {
    QMetaObject::invokeMethod(gui_app(), "getFileFromDialogBox",
                              Qt::BlockingQueuedConnection);
    bool r = load(image,
                  gui_app()->dialogBoxInfo.filename.toLocal8Bit().constData());
    return r;
  }

  bool load_from_dialog_box(Image<Color3ub>& image)
  {
    QMetaObject::invokeMethod(gui_app(), "getFileFromDialogBox",
                              Qt::BlockingQueuedConnection);
    bool r = load(image,
      std::string(gui_app()->dialogBoxInfo.filename.toLocal8Bit().constData()));
    return r;
  }

  static
  bool saveColorImage(const std::string& name, const Color3ub *cols,
                      int w, int h, int quality)
  {
    return QImage(reinterpret_cast<const unsigned char*>(cols),
                  w, h, w*3, QImage::Format_RGB888).
      save(QString(name.c_str()), 0, quality);
  }

  static
  bool saveGreyImage(const std::string& name, const unsigned char *g,
                     int w, int h, int quality)
  {
    QImage image(g, w, h, w, QImage::Format_Indexed8);
    QVector<QRgb> colorTable(256);
    for (int i = 0; i < 256; ++i)
      colorTable[i] = qRgb(i, i, i);
    image.setColorTable(colorTable);
    return image.save(QString(name.c_str()), 0, quality);
  }

  bool save(const Image<unsigned char>& I, const std::string& name,
            int quality)
  {
    return saveGreyImage(name, I.data(), I.width(), I.height(), quality);
  }

  bool save(const Image<Rgb8>& I, const std::string& name, int quality)
  {
    return saveColorImage(name, I.data(), I.width(), I.height(), quality);
  }

} /* namespace Sara */
} /* namespace DO */
<commit_msg>BUG: fixing once again the image load function.<commit_after>// ========================================================================== //
// This file is part of DO-CV, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2013 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <DO/Sara/Graphics.hpp>

#include "GraphicsUtilities.hpp"

namespace DO { namespace Sara {

  bool load(Image<Color3ub>& I, const std::string& name)
  {
    QImage image(QString(name.c_str()));
    if (image.isNull())
      return false;
    image = image.convertToFormat(QImage::Format_RGB888);
    I.resize(image.width(), image.height());

    Color3ub *dst = I.data();
    Color3ub *src = reinterpret_cast<Color3ub *>(image.bits());
    std::copy(src, src+image.width()*image.height(), dst);
    return true;
  }

  bool load(Image<Rgb8>& image, const std::string& name)
  {
    QImage qimage(QString(name.c_str()));
    if (qimage.isNull())
      return false;
    qimage = qimage.convertToFormat(QImage::Format_RGB32);
    if (qimage.format() != QImage::Format_RGB32)
      throw std::runtime_error("Failed to convert image to format RGB32");
    image.resize(qimage.width(), qimage.height());
    const int *src = reinterpret_cast<const int *>(qimage.constBits());
    for (Rgb8 *dst = image.data(); dst != image.end(); ++dst, ++src)
    {
      (*dst)[0] = *src >> 16;
      (*dst)[1] = *src >> 8;
      (*dst)[2] = *src;
    }
    return true;
  }

  bool load_from_dialog_box(Image<Rgb8>& image)
  {
    QMetaObject::invokeMethod(gui_app(), "getFileFromDialogBox",
                              Qt::BlockingQueuedConnection);
    bool r = load(image,
                  gui_app()->dialogBoxInfo.filename.toLocal8Bit().constData());
    return r;
  }

  bool load_from_dialog_box(Image<Color3ub>& image)
  {
    QMetaObject::invokeMethod(gui_app(), "getFileFromDialogBox",
                              Qt::BlockingQueuedConnection);
    bool r = load(image,
      std::string(gui_app()->dialogBoxInfo.filename.toLocal8Bit().constData()));
    return r;
  }

  static
  bool saveColorImage(const std::string& name, const Color3ub *cols,
                      int w, int h, int quality)
  {
    return QImage(reinterpret_cast<const unsigned char*>(cols),
                  w, h, w*3, QImage::Format_RGB888).
      save(QString(name.c_str()), 0, quality);
  }

  static
  bool saveGreyImage(const std::string& name, const unsigned char *g,
                     int w, int h, int quality)
  {
    QImage image(g, w, h, w, QImage::Format_Indexed8);
    QVector<QRgb> colorTable(256);
    for (int i = 0; i < 256; ++i)
      colorTable[i] = qRgb(i, i, i);
    image.setColorTable(colorTable);
    return image.save(QString(name.c_str()), 0, quality);
  }

  bool save(const Image<unsigned char>& I, const std::string& name,
            int quality)
  {
    return saveGreyImage(name, I.data(), I.width(), I.height(), quality);
  }

  bool save(const Image<Rgb8>& I, const std::string& name, int quality)
  {
    return saveColorImage(name, I.data(), I.width(), I.height(), quality);
  }

} /* namespace Sara */
} /* namespace DO */
<|endoftext|>


<commit_before>#pragma once

#include <map>
#include <array>
#include <numeric>

#include "acmacs-base/stream.hh"
#include "acmacs-base/fmt.hh"

// ----------------------------------------------------------------------

namespace acmacs
{
    template <typename Obj> class Counter
    {
     public:
        using container_type = std::map<Obj, size_t>;
        using value_type = typename container_type::value_type;

        Counter() = default;
        template <typename Iter, typename F> Counter(Iter first, Iter last, F func)
            {
                for (; first != last; ++first)
                    ++counter_[func(*first)];
            }
        template <typename Container, typename F> Counter(const Container& container, F func) : Counter(std::begin(container), std::end(container), func) {}

        template <typename S> void count(const S& aObj) { ++counter_[Obj{aObj}]; }
        template <typename S> void count_if(bool cond, const S& aObj) { if (cond) ++counter_[Obj{aObj}]; }

        const auto& max() const { return *std::max_element(counter_.begin(), counter_.end(), [](const auto& e1, const auto& e2) { return e1.second < e2.second; }); }

        auto sorted_max_first() const
            {
                std::vector<const value_type*> result(counter_.size());
                std::transform(std::begin(counter_), std::end(counter_), std::begin(result), [](const auto& ee) { return ⅇ });
                std::sort(result.begin(), result.end(), [](const auto& e1, const auto& e2) { return e1->second > e2->second; });
                return result;
            }

        constexpr const auto& counter() const { return counter_; }
        constexpr size_t size() const { return counter_.size(); }
        constexpr bool empty() const { return counter_.empty(); }

        template <typename S> size_t operator[](const S& look_for) const
        {
            if (const auto found = counter_.find(look_for); found != counter_.end())
                return found->second;
            else
                return 0;
        }

        std::string report(std::string_view format) const
        {
            fmt::memory_buffer out;
            for (const auto& entry : counter_)
                format_entry(out, format, entry);
            return fmt::to_string(out);
        }

        std::string report() const { return report("{value}  {counter:6d}\n"); }

        std::string report_sorted_max_first(std::string_view format) const
        {
            fmt::memory_buffer out;
            for (const auto& entry : sorted_max_first())
                format_entry(out, format, *entry);
            return fmt::to_string(out);
        }

        std::string report_sorted_max_first() const { return report_sorted_max_first("{counter:6d} {value}\n"); }

        size_t total() const
        {
            return std::accumulate(std::begin(counter_), std::end(counter_), 0UL, [](size_t sum, const auto& en) { return sum + en.second; });
        }

     private:
        container_type counter_;

        void format_entry(fmt::memory_buffer& out, std::string_view format, const value_type& entry) const
        {
                fmt::format_to(out, format, fmt::arg("quoted", fmt::format("\"{}\"", entry.first)), fmt::arg("value", entry.first), fmt::arg("counter", entry.second),
                               fmt::arg("first", entry.first), fmt::arg("quoted_first", fmt::format("\"{}\"", entry.first)), fmt::arg("second", entry.second));
        }

    }; // class Counter<Obj>

    template <typename Iter, typename F> Counter(Iter first, Iter last, F func) -> Counter<decltype(func(*first))>;
    template <typename Container, typename F> Counter(const Container& cont, F func) -> Counter<decltype(func(*std::begin(cont)))>;

    class CounterChar
    {
      public:
        CounterChar() { std::fill(std::begin(counter_), std::end(counter_), 0UL); }
        template <typename Iter, typename F> CounterChar(Iter first, Iter last, F func)
            : CounterChar()
        {
            for (; first != last; ++first)
                ++counter_[func(*first)];
        }
        template <typename Iter> CounterChar(Iter first, Iter last)
            : CounterChar()
        {
            for (; first != last; ++first)
                ++counter_[static_cast<size_t>(*first)];
        }
        template <typename Container, typename F> CounterChar(const Container& container, F func) : CounterChar(std::begin(container), std::end(container), func) {}
        template <typename Container> CounterChar(const Container& container) : CounterChar(std::begin(container), std::end(container)) {}

        void count(char aObj) { ++counter_[static_cast<unsigned char>(aObj)]; }

        bool empty() const { return std::all_of(std::begin(counter_), std::end(counter_), [](size_t val) { return val == 0; }); }
        size_t size() const { return static_cast<size_t>(std::count_if(std::begin(counter_), std::end(counter_), [](size_t val) { return val > 0UL; })); }
        size_t total() const { return std::accumulate(std::begin(counter_), std::end(counter_), 0UL, [](size_t sum, size_t val) { return sum + val; }); }

        std::pair<char, size_t> max() const
        {
            const auto me = std::max_element(counter_.begin(), counter_.end(), [](size_t e1, size_t e2) { return e1 < e2; });
            return {static_cast<char>(me - counter_.begin()), *me};
        }

        std::vector<char> sorted() const
        {
            std::vector<char> res;
            for (auto it = std::begin(counter_); it != std::end(counter_); ++it) {
                if (*it > 0)
                    res.push_back(static_cast<char>(it - std::begin(counter_)));
            }
            std::sort(std::begin(res), std::end(res), [this](auto e1, auto e2) { return counter_[static_cast<size_t>(e1)] > counter_[static_cast<size_t>(e2)]; });
            return res;
        }

        enum class sorted { no, yes };
        std::vector<std::pair<char, size_t>> pairs(enum sorted srt) const
        {
            std::vector<std::pair<char, size_t>> result;
            for (auto it = std::begin(counter_); it != std::end(counter_); ++it) {
                if (*it > 0)
                    result.emplace_back(static_cast<char>(it - std::begin(counter_)), *it);
            }
            if (srt == sorted::yes)
                std::sort(std::begin(result), std::end(result), [](const auto& e1, const auto& e2) { return e1.second > e2.second; });
            return result;
        }

        std::string report(std::string_view format) const
        {
            fmt::memory_buffer out;
            for (const auto& entry : pairs(sorted::no))
                format_entry(out, format, entry);
            return fmt::to_string(out);
        }

        std::string report() const { return report_sorted_max_first("{value} {counter:6d}\n"); }

        std::string report_sorted_max_first(std::string_view format) const
        {
            fmt::memory_buffer out;
            for (const auto& entry : pairs(sorted::yes))
                format_entry(out, format, entry);
            return fmt::to_string(out);
        }

        std::string report_sorted_max_first() const { return report_sorted_max_first("{counter:6d} {value}\n"); }

        size_t operator[](char val) const { return counter_[static_cast<size_t>(val)]; }

        constexpr const auto& counter() const { return counter_; }

      private:
        std::array<size_t, 256> counter_;

        void format_entry(fmt::memory_buffer& out, std::string_view format, const std::pair<char, size_t>& entry) const
        {
                fmt::format_to(out, format, fmt::arg("value", entry.first), fmt::arg("counter", entry.second),
                               fmt::arg("first", entry.first), fmt::arg("quoted_first", fmt::format("\"{}\"", entry.first)), fmt::arg("second", entry.second));
        }

    };

} // namespace acmacs

// ----------------------------------------------------------------------

template <typename Key> struct fmt::formatter<acmacs::Counter<Key>> : public fmt::formatter<acmacs::fmt_helper::default_formatter>
{
    template <typename FormatContext> auto format(const acmacs::Counter<Key>& counter, FormatContext& ctx)
    {
        return format_to(ctx.out(), "counter{{{}}}", counter.counter());
    }
};

template <> struct fmt::formatter<acmacs::CounterChar> : public fmt::formatter<acmacs::fmt_helper::default_formatter>
{
    template <typename FormatContext> auto format(const acmacs::CounterChar& counter, FormatContext& ctx)
    {
        auto out = format_to(ctx.out(), "counter{{");
        const auto keys = counter.sorted();
        for (auto it = keys.begin(); it != keys.end(); ++it) {
            if (it != keys.begin())
                out = format_to(out, ", ");
            out = format_to(out, "{}: {}", *it, counter[*it]);
        }
        return format_to(out, "}}");
    }
};

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>CounterChar improvements<commit_after>#pragma once

#include <map>
#include <array>
#include <numeric>

#include "acmacs-base/stream.hh"
#include "acmacs-base/fmt.hh"

// ----------------------------------------------------------------------

namespace acmacs
{
    template <typename Obj> class Counter
    {
     public:
        using container_type = std::map<Obj, size_t>;
        using value_type = typename container_type::value_type;

        Counter() = default;
        template <typename Iter, typename F> Counter(Iter first, Iter last, F func)
            {
                for (; first != last; ++first)
                    ++counter_[func(*first)];
            }
        template <typename Container, typename F> Counter(const Container& container, F func) : Counter(std::begin(container), std::end(container), func) {}

        template <typename S> void count(const S& aObj) { ++counter_[Obj{aObj}]; }
        template <typename S> void count_if(bool cond, const S& aObj) { if (cond) ++counter_[Obj{aObj}]; }

        const auto& max() const { return *std::max_element(counter_.begin(), counter_.end(), [](const auto& e1, const auto& e2) { return e1.second < e2.second; }); }

        auto sorted_max_first() const
            {
                std::vector<const value_type*> result(counter_.size());
                std::transform(std::begin(counter_), std::end(counter_), std::begin(result), [](const auto& ee) { return ⅇ });
                std::sort(result.begin(), result.end(), [](const auto& e1, const auto& e2) { return e1->second > e2->second; });
                return result;
            }

        constexpr const auto& counter() const { return counter_; }
        constexpr size_t size() const { return counter_.size(); }
        constexpr bool empty() const { return counter_.empty(); }

        template <typename S> size_t operator[](const S& look_for) const
        {
            if (const auto found = counter_.find(look_for); found != counter_.end())
                return found->second;
            else
                return 0;
        }

        std::string report(std::string_view format) const
        {
            fmt::memory_buffer out;
            for (const auto& entry : counter_)
                format_entry(out, format, entry);
            return fmt::to_string(out);
        }

        std::string report() const { return report("{value}  {counter:6d}\n"); }

        std::string report_sorted_max_first(std::string_view format) const
        {
            fmt::memory_buffer out;
            for (const auto& entry : sorted_max_first())
                format_entry(out, format, *entry);
            return fmt::to_string(out);
        }

        std::string report_sorted_max_first() const { return report_sorted_max_first("{counter:6d} {value}\n"); }

        size_t total() const
        {
            return std::accumulate(std::begin(counter_), std::end(counter_), 0UL, [](size_t sum, const auto& en) { return sum + en.second; });
        }

     private:
        container_type counter_;

        void format_entry(fmt::memory_buffer& out, std::string_view format, const value_type& entry) const
        {
                fmt::format_to(out, format, fmt::arg("quoted", fmt::format("\"{}\"", entry.first)), fmt::arg("value", entry.first), fmt::arg("counter", entry.second),
                               fmt::arg("first", entry.first), fmt::arg("quoted_first", fmt::format("\"{}\"", entry.first)), fmt::arg("second", entry.second));
        }

    }; // class Counter<Obj>

    template <typename Iter, typename F> Counter(Iter first, Iter last, F func) -> Counter<decltype(func(*first))>;
    template <typename Container, typename F> Counter(const Container& cont, F func) -> Counter<decltype(func(*std::begin(cont)))>;

    template <size_t first_char = 0, size_t last_char = 256, typename counter_t_t = uint32_t> class CounterCharSome
    {
      public:
        using counter_t = counter_t_t;

        CounterCharSome() { std::fill(std::begin(counter_), std::end(counter_), counter_t{0}); }
        template <typename Iter, typename F> CounterCharSome(Iter first, Iter last, F func)
            : CounterCharSome()
        {
            for (; first != last; ++first)
                ++counter_[func(*first) - first_char];
        }
        template <typename Iter> CounterCharSome(Iter first, Iter last)
            : CounterCharSome()
        {
            for (; first != last; ++first)
                ++counter_[static_cast<size_t>(*first) - first_char];
        }
        template <typename Container, typename F> CounterCharSome(const Container& container, F func) : CounterCharSome(std::begin(container), std::end(container), func) {}
        template <typename Container> CounterCharSome(const Container& container) : CounterCharSome(std::begin(container), std::end(container)) {}

        void count(char aObj) { ++counter_[static_cast<unsigned char>(aObj) - first_char]; }

        bool empty() const { return std::all_of(std::begin(counter_), std::end(counter_), [](counter_t val) { return val == 0; }); }
        size_t size() const { return static_cast<size_t>(std::count_if(std::begin(counter_), std::end(counter_), [](counter_t val) { return val > counter_t{0}; })); }
        counter_t total() const { return std::accumulate(std::begin(counter_), std::end(counter_), counter_t{0}, [](counter_t sum, counter_t val) { return sum + val; }); }

        std::pair<char, counter_t> max() const
        {
            const auto me = std::max_element(counter_.begin(), counter_.end(), [](counter_t e1, counter_t e2) { return e1 < e2; });
            return {static_cast<char>(me - counter_.begin() + static_cast<ssize_t>(first_char)), *me};
        }

        std::vector<char> sorted() const
        {
            std::vector<char> res;
            for (auto it = std::begin(counter_); it != std::end(counter_); ++it) {
                if (*it > 0)
                    res.push_back(static_cast<char>(it - std::begin(counter_) + static_cast<ssize_t>(first_char)));
            }
            std::sort(std::begin(res), std::end(res), [this](auto e1, auto e2) { return counter_[static_cast<size_t>(e1) - first_char] > counter_[static_cast<size_t>(e2) - first_char]; });
            return res;
        }

        enum class sorted { no, yes };
        std::vector<std::pair<char, counter_t>> pairs(enum sorted srt) const
        {
            std::vector<std::pair<char, counter_t>> result;
            for (auto it = std::begin(counter_); it != std::end(counter_); ++it) {
                if (*it > 0)
                    result.emplace_back(static_cast<char>(it - std::begin(counter_) + static_cast<ssize_t>(first_char)), *it);
            }
            if (srt == sorted::yes)
                std::sort(std::begin(result), std::end(result), [](const auto& e1, const auto& e2) { return e1.second > e2.second; });
            return result;
        }

        std::string report(std::string_view format) const
        {
            fmt::memory_buffer out;
            for (const auto& entry : pairs(sorted::no))
                format_entry(out, format, entry);
            return fmt::to_string(out);
        }

        std::string report() const { return report_sorted_max_first("{value} {counter:6d}\n"); }

        std::string report_sorted_max_first(std::string_view format) const
        {
            fmt::memory_buffer out;
            for (const auto& entry : pairs(sorted::yes))
                format_entry(out, format, entry);
            return fmt::to_string(out);
        }

        std::string report_sorted_max_first() const { return report_sorted_max_first("{counter:6d} {value}\n"); }

        counter_t operator[](char val) const { return counter_[static_cast<size_t>(val) - first_char]; }

        constexpr const auto& counter() const { return counter_; }

      private:
        std::array<counter_t, last_char - first_char> counter_;

        void format_entry(fmt::memory_buffer& out, std::string_view format, const std::pair<char, counter_t>& entry) const
        {
                fmt::format_to(out, format, fmt::arg("value", entry.first), fmt::arg("counter", entry.second),
                               fmt::arg("first", entry.first), fmt::arg("quoted_first", fmt::format("\"{}\"", entry.first)), fmt::arg("second", entry.second));
        }

    };

    using CounterChar = CounterCharSome<0, 256, uint32_t>;

} // namespace acmacs

// ----------------------------------------------------------------------

template <typename Key> struct fmt::formatter<acmacs::Counter<Key>> : public fmt::formatter<acmacs::fmt_helper::default_formatter>
{
    template <typename FormatContext> auto format(const acmacs::Counter<Key>& counter, FormatContext& ctx)
    {
        return format_to(ctx.out(), "counter{{{}}}", counter.counter());
    }
};

template <> struct fmt::formatter<acmacs::CounterChar> : public fmt::formatter<acmacs::fmt_helper::default_formatter>
{
    template <typename FormatContext> auto format(const acmacs::CounterChar& counter, FormatContext& ctx)
    {
        auto out = format_to(ctx.out(), "counter{{");
        const auto keys = counter.sorted();
        for (auto it = keys.begin(); it != keys.end(); ++it) {
            if (it != keys.begin())
                out = format_to(out, ", ");
            out = format_to(out, "{}: {}", *it, counter[*it]);
        }
        return format_to(out, "}}");
    }
};

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2017, John Haddon. 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 John Haddon nor the names of
//        any other contributors to this software 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.
//
//////////////////////////////////////////////////////////////////////////

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>

#include "openvdb/openvdb.h"
#include "openvdb/tools/VolumeToMesh.h"

#include "IECore/MeshPrimitive.h"

#include "Gaffer/StringPlug.h"

#include "GafferVDB/VDBObject.h"
#include "GafferVDB/LevelSetToMesh.h"

using namespace std;
using namespace Imath;
using namespace IECore;
using namespace Gaffer;
using namespace GafferVDB;

//////////////////////////////////////////////////////////////////////////
// Utilities. Perhaps these belong in Cortex one day?
//////////////////////////////////////////////////////////////////////////

namespace
{

//! list of grid types which can be converted to a mesh
//! AccorindCall with scalar typed grid.
typedef boost::mpl::list
<
	openvdb::BoolGrid,
	openvdb::DoubleGrid,
	openvdb::FloatGrid,
	openvdb::Int32Grid,
	openvdb::Int64Grid
> VDBScalarGridList;

struct Dispatcher
{
	Dispatcher( openvdb::GridBase::ConstPtr grid, openvdb::tools::VolumeToMesh &mesher ) : m_grid( grid ), m_mesher( mesher ), m_matchingTypeFound( false )
	{
	}

	template<typename GridType>
	void operator()( GridType )
	{
		if ( m_matchingTypeFound )
		{
			return;
		}

		if( typename GridType::ConstPtr t = openvdb::GridBase::constGrid<GridType>( m_grid ) )
		{
			m_matchingTypeFound = true;
			m_mesher( *t );
		}
	}

	openvdb::GridBase::ConstPtr m_grid;
	openvdb::tools::VolumeToMesh &m_mesher;
	bool m_matchingTypeFound;
};

IECore::MeshPrimitivePtr volumeToMesh( openvdb::GridBase::ConstPtr grid, double isoValue, double adaptivity )
{
	openvdb::tools::VolumeToMesh mesher( isoValue, adaptivity );
	boost::mpl::for_each<VDBScalarGridList> ( Dispatcher( grid, mesher ) );

	// Copy out topology

	IntVectorDataPtr verticesPerFaceData = new IntVectorData;
	vector<int> &verticesPerFace = verticesPerFaceData->writable();

	IntVectorDataPtr vertexIdsData = new IntVectorData;
	vector<int> &vertexIds = vertexIdsData->writable();

	size_t numPolygons = 0;
	size_t numVerts = 0;
	for( size_t i = 0, n = mesher.polygonPoolListSize(); i < n; ++i )
	{
		const openvdb::tools::PolygonPool &polygonPool = mesher.polygonPoolList()[i];
		numPolygons += polygonPool.numQuads() + polygonPool.numTriangles();
		numVerts += polygonPool.numQuads() * 4 + polygonPool.numTriangles() * 3;
	}

	verticesPerFace.reserve( numPolygons );
	vertexIds.reserve( numVerts );

	for( size_t i = 0, n = mesher.polygonPoolListSize(); i < n; ++i )
	{
		const openvdb::tools::PolygonPool &polygonPool = mesher.polygonPoolList()[i];
		for( size_t qi = 0, qn = polygonPool.numQuads(); qi < qn; ++qi )
		{
			openvdb::math::Vec4ui quad = polygonPool.quad( qi );
			verticesPerFace.push_back( 4 );
			vertexIds.push_back( quad[0] );
			vertexIds.push_back( quad[1] );
			vertexIds.push_back( quad[2] );
			vertexIds.push_back( quad[3] );
		}

		for( size_t ti = 0, tn = polygonPool.numTriangles(); ti < tn; ++ti )
		{
			openvdb::math::Vec3ui triangle = polygonPool.triangle( ti );
			verticesPerFace.push_back( 3 );
			vertexIds.push_back( triangle[0] );
			vertexIds.push_back( triangle[1] );
			vertexIds.push_back( triangle[2] );
		}
	}

	// Copy out points
	V3fVectorDataPtr pointsData = new V3fVectorData;
	vector<V3f> &points = pointsData->writable();

	points.reserve( mesher.pointListSize() );
	for( size_t i = 0, n = mesher.pointListSize(); i < n; ++i )
	{
		const openvdb::math::Vec3s v = mesher.pointList()[i];
		points.push_back( V3f( v.x(), v.y(), v.z() ) );
	}

	return new MeshPrimitive( verticesPerFaceData, vertexIdsData, "linear", pointsData );
}

} // namespace

//////////////////////////////////////////////////////////////////////////
// VolumeToMesh implementation
//////////////////////////////////////////////////////////////////////////

IE_CORE_DEFINERUNTIMETYPED( LevelSetToMesh );

size_t LevelSetToMesh::g_firstPlugIndex = 0;

LevelSetToMesh::LevelSetToMesh( const std::string &name )
	:	SceneElementProcessor( name )
{
	storeIndexOfNextChild( g_firstPlugIndex );

	addChild( new StringPlug( "gridName", Plug::In, "levelset" ) );
	addChild( new FloatPlug( "isoValue", Plug::In, 0.0f ) );
	addChild( new FloatPlug( "adaptivity", Plug::In, 0.0f, 0.0f, 1.0f ) );

}

LevelSetToMesh::~LevelSetToMesh()
{
}

Gaffer::StringPlug *LevelSetToMesh::gridNamePlug()
{
	return  getChild<StringPlug>( g_firstPlugIndex );
}

const Gaffer::StringPlug *LevelSetToMesh::gridNamePlug() const
{
	return  getChild<StringPlug>( g_firstPlugIndex );
}

Gaffer::FloatPlug *LevelSetToMesh::isoValuePlug()
{
	return getChild<FloatPlug>( g_firstPlugIndex + 1);
}

const Gaffer::FloatPlug *LevelSetToMesh::isoValuePlug() const
{
	return getChild<FloatPlug>( g_firstPlugIndex + 1);
}

Gaffer::FloatPlug *LevelSetToMesh::adaptivityPlug()
{
	return getChild<FloatPlug>( g_firstPlugIndex + 2 );
}

const Gaffer::FloatPlug *LevelSetToMesh::adaptivityPlug() const
{
	return getChild<FloatPlug>( g_firstPlugIndex + 2 );
}

void LevelSetToMesh::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const
{
	SceneElementProcessor::affects( input, outputs );

	if(
		input == isoValuePlug() ||
		input == adaptivityPlug() ||
		input == gridNamePlug()
	)
	{
		outputs.push_back( outPlug()->objectPlug() );
	}
}

bool LevelSetToMesh::processesObject() const
{
	return true;
}

void LevelSetToMesh::hashProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
	SceneElementProcessor::hashProcessedObject( path, context, h );

	gridNamePlug()->hash( h );
	isoValuePlug()->hash( h );
	adaptivityPlug()->hash( h );
}

IECore::ConstObjectPtr LevelSetToMesh::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
	const VDBObject *vdbObject = runTimeCast<const VDBObject>( inputObject.get() );
	if( !vdbObject )
	{
		return inputObject;
	}

	openvdb::GridBase::ConstPtr grid = vdbObject->findGrid( gridNamePlug()->getValue() );

	if (!grid)
	{
		return inputObject;
	}

	return volumeToMesh( grid, isoValuePlug()->getValue(), adaptivityPlug()->getValue() );
}
<commit_msg>LevelSetToMesh : replaced MPL type dispatch with map of str -> function<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2017, John Haddon. 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 John Haddon nor the names of
//        any other contributors to this software 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.
//
//////////////////////////////////////////////////////////////////////////

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>

#include "openvdb/openvdb.h"
#include "openvdb/tools/VolumeToMesh.h"

#include "IECore/MeshPrimitive.h"

#include "Gaffer/StringPlug.h"

#include "GafferVDB/VDBObject.h"
#include "GafferVDB/LevelSetToMesh.h"

using namespace std;
using namespace Imath;
using namespace IECore;
using namespace Gaffer;
using namespace GafferVDB;

//////////////////////////////////////////////////////////////////////////
// Utilities. Perhaps these belong in Cortex one day?
//////////////////////////////////////////////////////////////////////////

namespace
{

struct MesherDispatch
{
	MesherDispatch( openvdb::GridBase::ConstPtr grid, openvdb::tools::VolumeToMesh &mesher ) : m_grid( grid ), m_mesher( mesher )
	{
	}

	template<typename GridType>
	void execute()
	{
		if( typename GridType::ConstPtr t = openvdb::GridBase::constGrid<GridType>( m_grid ) )
		{
			m_mesher( *t );
		}
	}

	openvdb::GridBase::ConstPtr m_grid;
	openvdb::tools::VolumeToMesh &m_mesher;
};

static std::map<std::string, std::function<void( MesherDispatch& dispatch )> > meshers =
{
	{ openvdb::typeNameAsString<bool>(), []( MesherDispatch& dispatch ) { dispatch.execute<openvdb::BoolGrid>(); } },
	{ openvdb::typeNameAsString<double>(), []( MesherDispatch& dispatch ) { dispatch.execute<openvdb::DoubleGrid>(); } },
	{ openvdb::typeNameAsString<float>(), []( MesherDispatch& dispatch ) { dispatch.execute<openvdb::FloatGrid>(); } },
	{ openvdb::typeNameAsString<int32_t>(), []( MesherDispatch& dispatch ) { dispatch.execute<openvdb::Int32Grid>(); } },
	{ openvdb::typeNameAsString<int64_t>(), []( MesherDispatch& dispatch ) { dispatch.execute<openvdb::Int64Grid>(); } }
};

IECore::MeshPrimitivePtr volumeToMesh( openvdb::GridBase::ConstPtr grid, double isoValue, double adaptivity )
{
	openvdb::tools::VolumeToMesh mesher( isoValue, adaptivity );
	MesherDispatch dispatch( grid, mesher );

	const auto it = meshers.find( grid->valueType() );
	if( it != meshers.end() )
	{
		it->second( dispatch );
	}
	else
	{
		throw IECore::InvalidArgumentException( boost::str( boost::format( "Incompatible Grid found name: '%1%' type: '%2' " ) % grid->valueType() % grid->getName() ) );
	}

	// Copy out topology
	IntVectorDataPtr verticesPerFaceData = new IntVectorData;
	vector<int> &verticesPerFace = verticesPerFaceData->writable();

	IntVectorDataPtr vertexIdsData = new IntVectorData;
	vector<int> &vertexIds = vertexIdsData->writable();

	size_t numPolygons = 0;
	size_t numVerts = 0;
	for( size_t i = 0, n = mesher.polygonPoolListSize(); i < n; ++i )
	{
		const openvdb::tools::PolygonPool &polygonPool = mesher.polygonPoolList()[i];
		numPolygons += polygonPool.numQuads() + polygonPool.numTriangles();
		numVerts += polygonPool.numQuads() * 4 + polygonPool.numTriangles() * 3;
	}

	verticesPerFace.reserve( numPolygons );
	vertexIds.reserve( numVerts );

	for( size_t i = 0, n = mesher.polygonPoolListSize(); i < n; ++i )
	{
		const openvdb::tools::PolygonPool &polygonPool = mesher.polygonPoolList()[i];
		for( size_t qi = 0, qn = polygonPool.numQuads(); qi < qn; ++qi )
		{
			openvdb::math::Vec4ui quad = polygonPool.quad( qi );
			verticesPerFace.push_back( 4 );
			vertexIds.push_back( quad[0] );
			vertexIds.push_back( quad[1] );
			vertexIds.push_back( quad[2] );
			vertexIds.push_back( quad[3] );
		}

		for( size_t ti = 0, tn = polygonPool.numTriangles(); ti < tn; ++ti )
		{
			openvdb::math::Vec3ui triangle = polygonPool.triangle( ti );
			verticesPerFace.push_back( 3 );
			vertexIds.push_back( triangle[0] );
			vertexIds.push_back( triangle[1] );
			vertexIds.push_back( triangle[2] );
		}
	}

	// Copy out points
	V3fVectorDataPtr pointsData = new V3fVectorData;
	vector<V3f> &points = pointsData->writable();

	points.reserve( mesher.pointListSize() );
	for( size_t i = 0, n = mesher.pointListSize(); i < n; ++i )
	{
		const openvdb::math::Vec3s v = mesher.pointList()[i];
		points.push_back( V3f( v.x(), v.y(), v.z() ) );
	}

	return new MeshPrimitive( verticesPerFaceData, vertexIdsData, "linear", pointsData );
}

} // namespace

//////////////////////////////////////////////////////////////////////////
// VolumeToMesh implementation
//////////////////////////////////////////////////////////////////////////

IE_CORE_DEFINERUNTIMETYPED( LevelSetToMesh );

size_t LevelSetToMesh::g_firstPlugIndex = 0;

LevelSetToMesh::LevelSetToMesh( const std::string &name )
	:	SceneElementProcessor( name )
{
	storeIndexOfNextChild( g_firstPlugIndex );

	addChild( new StringPlug( "gridName", Plug::In, "levelset" ) );
	addChild( new FloatPlug( "isoValue", Plug::In, 0.0f ) );
	addChild( new FloatPlug( "adaptivity", Plug::In, 0.0f, 0.0f, 1.0f ) );

}

LevelSetToMesh::~LevelSetToMesh()
{
}

Gaffer::StringPlug *LevelSetToMesh::gridNamePlug()
{
	return  getChild<StringPlug>( g_firstPlugIndex );
}

const Gaffer::StringPlug *LevelSetToMesh::gridNamePlug() const
{
	return  getChild<StringPlug>( g_firstPlugIndex );
}

Gaffer::FloatPlug *LevelSetToMesh::isoValuePlug()
{
	return getChild<FloatPlug>( g_firstPlugIndex + 1);
}

const Gaffer::FloatPlug *LevelSetToMesh::isoValuePlug() const
{
	return getChild<FloatPlug>( g_firstPlugIndex + 1);
}

Gaffer::FloatPlug *LevelSetToMesh::adaptivityPlug()
{
	return getChild<FloatPlug>( g_firstPlugIndex + 2 );
}

const Gaffer::FloatPlug *LevelSetToMesh::adaptivityPlug() const
{
	return getChild<FloatPlug>( g_firstPlugIndex + 2 );
}

void LevelSetToMesh::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const
{
	SceneElementProcessor::affects( input, outputs );

	if(
		input == isoValuePlug() ||
		input == adaptivityPlug() ||
		input == gridNamePlug()
	)
	{
		outputs.push_back( outPlug()->objectPlug() );
	}
}

bool LevelSetToMesh::processesObject() const
{
	return true;
}

void LevelSetToMesh::hashProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
	SceneElementProcessor::hashProcessedObject( path, context, h );

	gridNamePlug()->hash( h );
	isoValuePlug()->hash( h );
	adaptivityPlug()->hash( h );
}

IECore::ConstObjectPtr LevelSetToMesh::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
	const VDBObject *vdbObject = runTimeCast<const VDBObject>( inputObject.get() );
	if( !vdbObject )
	{
		return inputObject;
	}

	openvdb::GridBase::ConstPtr grid = vdbObject->findGrid( gridNamePlug()->getValue() );

	if (!grid)
	{
		return inputObject;
	}

	return volumeToMesh( grid, isoValuePlug()->getValue(), adaptivityPlug()->getValue() );
}
<|endoftext|>


<commit_before>#include "Segment.hpp"

ppSegment::ppSegment(const char *name, ppIMS* ims) : ppGenericSound(), ppControl(name, 0, 0){
	this->ims = ims;
	this->emptySound = NULL;
}

ppSegment::~ppSegment(){
	ppGenericSound::~ppGenericSound();
	if(this->emptySound){
		delete this->emptySound;
	}
}

void ppSegment::AddSound(ppGenericSound *sound){
	this->sounds.push_back(sound);

	if(this->emptySound){
		delete this->emptySound;
	}
	Sint64 maxtime = 0;
	for(auto sound : this->sounds){
		if(maxtime<sound->GetOffset()+sound->GetPositionLength()){
			maxtime = sound->GetOffset()+sound->GetPositionLength();
		}
	}
	this->emptySound = new ppSound("_empty", ims->CreateEmptyFormat(maxtime), 1);
}

void ppSegment::ClearSound(){
	this->sounds.clear();
}

Sint64 ppSegment::GetCurrentPosition(){
	return this->emptySound->GetCurrentPosition();
}

Sint64 ppSegment::GetPositionLength(){
	return this->emptySound->GetPositionLength();
}

float ppSegment::GetCurrentTime(){
	return this->emptySound->GetCurrentTime();
}

float ppSegment::GetTotalTime(){
	return this->emptySound->GetTotalTime();
}

void ppSegment::SetLoop(int loop){
	this->emptySound->SetLoop(loop);
}

void ppSegment::Play(){
	this->emptySound->Play();
}

void ppSegment::Pause(){
	this->emptySound->Pause();
	for(auto sound : this->sounds){
		sound->Pause();
	}
}

void ppSegment::Stop(){
	this->emptySound->Stop();
	for(auto sound : this->sounds){
		sound->Stop();
	}
}

void ppSegment::Update(){
	this->emptySound->Update();
	for(auto sound : this->sounds){
		if(sound->GetOffset()<this->GetCurrentPosition() && sound->IsStop() && this->GetCurrentPosition() < sound->GetPositionLength()){
			sound->Play();
		}else if(!sound->IsStop()){
			sound->Stop();
		}
		sound->Update();
	}
}

void ppSegment::Render(SDL_Renderer* renderer){
	ppControl::Render(renderer);
	if(!this->visible){
		return;
	}
	//Border
	glBegin(GL_LINE_LOOP);
	{
		glColor3f(1, 1, 1);
		glVertex3f(this->x, this->y, 0);
		glVertex3f(this->x+this->width, this->y, 0);
		glVertex3f(this->x+this->width, this->y+this->height, 0);
		glVertex3f(this->x, this->y+this->height, 0);
	}
	glEnd();
	//Playing Cursor
	glBegin(GL_LINES);
	{
		glColor3f(0.7f, 0.7f, 1);
		int offset = this->GetCurrentTime()*(this->width-2)/this->GetTotalTime();
		glVertex3f(this->x+offset, this->y+1, 0);
		glVertex3f(this->x+offset, this->y+this->height, 0);
	}
	glEnd();
	int index=1;
	int height=this->height/(this->sounds.size()+1);
	glBegin(GL_QUADS);
	{
		glColor4f(0.8f, 0.5f, 0.5f, 1);
		// int width = this->audioFormat->ActualPosition(this->totalBufferProcessed*this->bufferSize)*(this->width-2)/this->GetPositionLength();
		int width = this->GetCurrentPosition()*(this->width-2)/this->GetPositionLength();
		glVertex3f(this->x, this->y+1, 0);
		glVertex3f(this->x+width, this->y+1, 0);
		glVertex3f(this->x+width, this->y+height, 0);
		glVertex3f(this->x, this->y+height, 0);
	}
	glEnd();
	for(auto sound : this->sounds){
		int offset_width = sound->GetOffset()*(this->width-2)/this->GetPositionLength();
		int width = sound->GetCurrentPosition()*(this->width-2)/this->GetPositionLength();
		int max_width = sound->GetPositionLength()*(this->width-2)/this->GetPositionLength();
		//Total playing time
		glBegin(GL_QUADS);
		{
			glColor4f(0.3f+(0.2f*(index%2)), 0.3f+(0.2f*(index%2)), 0.3f+(0.2f*(index%2)), 1);
			glVertex3f(this->x+offset_width+width, this->y+(index*height)+1, 0);
			glVertex3f(this->x+offset_width+max_width, this->y+(index*height)+1, 0);
			glVertex3f(this->x+offset_width+max_width, this->y+(index*height)+height, 0);
			glVertex3f(this->x+offset_width+width, this->y+(index*height)+height, 0);
		}
		glEnd();
		//Current playing time
		glBegin(GL_QUADS);
		{
			glColor4f(0.5f, 0.5f+(0.3f*(index%2)), 0.5f+(0.3f*((index+1)%2)), 1);
			glVertex3f(this->x+offset_width, this->y+(index*height)+1, 0);
			glVertex3f(this->x+offset_width+width, this->y+(index*height)+1, 0);
			glVertex3f(this->x+offset_width+width, this->y+(index*height)+height, 0);
			glVertex3f(this->x+offset_width, this->y+(index*height)+height, 0);
		}
		glEnd();
		index++;
	}
}

void ppSegment::Update(ppInput* input){
	ppControl::Update(input);
}

ppControlType ppSegment::GetType(){
	return ppControlType::SEGMENT_CONTROL;
}
<commit_msg>Fix sound glitch while offsetting<commit_after>#include "Segment.hpp"

ppSegment::ppSegment(const char *name, ppIMS* ims) : ppGenericSound(), ppControl(name, 0, 0){
	this->ims = ims;
	this->emptySound = NULL;
}

ppSegment::~ppSegment(){
	ppGenericSound::~ppGenericSound();
	if(this->emptySound){
		delete this->emptySound;
	}
}

void ppSegment::AddSound(ppGenericSound *sound){
	this->sounds.push_back(sound);

	if(this->emptySound){
		delete this->emptySound;
	}
	Sint64 maxtime = 0;
	for(auto sound : this->sounds){
		if(maxtime<sound->GetOffset()+sound->GetPositionLength()){
			maxtime = sound->GetOffset()+sound->GetPositionLength();
		}
	}
	this->emptySound = new ppSound("_empty", ims->CreateEmptyFormat(maxtime), 1);
}

void ppSegment::ClearSound(){
	this->sounds.clear();
}

Sint64 ppSegment::GetCurrentPosition(){
	return this->emptySound->GetCurrentPosition();
}

Sint64 ppSegment::GetPositionLength(){
	return this->emptySound->GetPositionLength();
}

float ppSegment::GetCurrentTime(){
	return this->emptySound->GetCurrentTime();
}

float ppSegment::GetTotalTime(){
	return this->emptySound->GetTotalTime();
}

void ppSegment::SetLoop(int loop){
	this->emptySound->SetLoop(loop);
}

void ppSegment::Play(){
	this->emptySound->Play();
}

void ppSegment::Pause(){
	this->emptySound->Pause();
	for(auto sound : this->sounds){
		sound->Pause();
	}
}

void ppSegment::Stop(){
	this->emptySound->Stop();
	for(auto sound : this->sounds){
		sound->Stop();
	}
}

void ppSegment::Update(){
	this->emptySound->Update();
	for(auto sound : this->sounds){
		if(sound->GetOffset()<this->GetCurrentPosition() && sound->IsStop() && this->GetCurrentPosition() < sound->GetPositionLength()){
			sound->Play();
		}
		sound->Update();
	}
}

void ppSegment::Render(SDL_Renderer* renderer){
	ppControl::Render(renderer);
	if(!this->visible){
		return;
	}
	//Border
	glBegin(GL_LINE_LOOP);
	{
		glColor3f(1, 1, 1);
		glVertex3f(this->x, this->y, 0);
		glVertex3f(this->x+this->width, this->y, 0);
		glVertex3f(this->x+this->width, this->y+this->height, 0);
		glVertex3f(this->x, this->y+this->height, 0);
	}
	glEnd();
	//Playing Cursor
	glBegin(GL_LINES);
	{
		glColor3f(0.7f, 0.7f, 1);
		int offset = this->GetCurrentTime()*(this->width-2)/this->GetTotalTime();
		glVertex3f(this->x+offset, this->y+1, 0);
		glVertex3f(this->x+offset, this->y+this->height, 0);
	}
	glEnd();
	int index=1;
	int height=this->height/(this->sounds.size()+1);
	glBegin(GL_QUADS);
	{
		glColor4f(0.8f, 0.5f, 0.5f, 1);
		// int width = this->audioFormat->ActualPosition(this->totalBufferProcessed*this->bufferSize)*(this->width-2)/this->GetPositionLength();
		int width = this->GetCurrentPosition()*(this->width-2)/this->GetPositionLength();
		glVertex3f(this->x, this->y+1, 0);
		glVertex3f(this->x+width, this->y+1, 0);
		glVertex3f(this->x+width, this->y+height, 0);
		glVertex3f(this->x, this->y+height, 0);
	}
	glEnd();
	for(auto sound : this->sounds){
		int offset_width = sound->GetOffset()*(this->width-2)/this->GetPositionLength();
		int width = sound->GetCurrentPosition()*(this->width-2)/this->GetPositionLength();
		int max_width = sound->GetPositionLength()*(this->width-2)/this->GetPositionLength();
		//Total playing time
		glBegin(GL_QUADS);
		{
			glColor4f(0.3f+(0.2f*(index%2)), 0.3f+(0.2f*(index%2)), 0.3f+(0.2f*(index%2)), 1);
			glVertex3f(this->x+offset_width+width, this->y+(index*height)+1, 0);
			glVertex3f(this->x+offset_width+max_width, this->y+(index*height)+1, 0);
			glVertex3f(this->x+offset_width+max_width, this->y+(index*height)+height, 0);
			glVertex3f(this->x+offset_width+width, this->y+(index*height)+height, 0);
		}
		glEnd();
		//Current playing time
		glBegin(GL_QUADS);
		{
			glColor4f(0.5f, 0.5f+(0.3f*(index%2)), 0.5f+(0.3f*((index+1)%2)), 1);
			glVertex3f(this->x+offset_width, this->y+(index*height)+1, 0);
			glVertex3f(this->x+offset_width+width, this->y+(index*height)+1, 0);
			glVertex3f(this->x+offset_width+width, this->y+(index*height)+height, 0);
			glVertex3f(this->x+offset_width, this->y+(index*height)+height, 0);
		}
		glEnd();
		index++;
	}
}

void ppSegment::Update(ppInput* input){
	ppControl::Update(input);
}

ppControlType ppSegment::GetType(){
	return ppControlType::SEGMENT_CONTROL;
}
<|endoftext|>


<commit_before>/*
  Copyright 2011-2012 David Robillard <http://drobilla.net>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <QX11EmbedContainer>
#undef signals

#include "./suil_config.h"
#include "./suil_internal.h"

extern "C" {

static int
wrapper_wrap(SuilWrapper*  wrapper,
             SuilInstance* instance)
{
	QX11EmbedWidget* const    ew   = (QX11EmbedWidget*)wrapper->impl;
	QX11EmbedContainer* const wrap = new QX11EmbedContainer();

	ew->embedInto(wrap->winId());

	instance->host_widget = wrap;

	return 0;
}

static int
wrapper_resize(LV2UI_Feature_Handle handle, int width, int height)
{
	QX11EmbedWidget* const ew = (QX11EmbedWidget*)handle;
	ew->resize(width, height);
	return 0;
}

SUIL_API
SuilWrapper*
suil_wrapper_new(SuilHost*                 host,
                 const char*               host_type_uri,
                 const char*               ui_type_uri,
                 const LV2_Feature* const* features)
{
	SuilWrapper* wrapper = (SuilWrapper*)malloc(sizeof(SuilWrapper));
	wrapper->wrap = wrapper_wrap;
	wrapper->free = (SuilWrapperFreeFunc)free;

	unsigned n_features = 0;
	for (; features[n_features]; ++n_features) {}

	QX11EmbedWidget* const ew = new QX11EmbedWidget();
	wrapper->impl = ew;

	wrapper->features = (LV2_Feature**)malloc(
		sizeof(LV2_Feature*) * (n_features + 3));
	memcpy(wrapper->features, features, sizeof(LV2_Feature*) * n_features);

	LV2_Feature* parent_feature = (LV2_Feature*)malloc(sizeof(LV2_Feature));
	parent_feature->URI  = NS_UI "parent";
	parent_feature->data = (void*)(intptr_t)ew->winId();

	wrapper->features[n_features]     = parent_feature;
	wrapper->features[n_features + 1] = NULL;
	wrapper->features[n_features + 2] = NULL;

	wrapper->resize.handle    = ew;
	wrapper->resize.ui_resize = wrapper_resize;

	LV2_Feature* resize_feature = (LV2_Feature*)malloc(sizeof(LV2_Feature));
	resize_feature->URI  = "http://lv2plug.in/ns/ext/ui-resize#UIResize";
	resize_feature->data = &wrapper->resize;
	wrapper->features[n_features + 1] = resize_feature;

	return wrapper;
}

}  // extern "C"
<commit_msg>Fix resize feature URI.<commit_after>/*
  Copyright 2011-2012 David Robillard <http://drobilla.net>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <QX11EmbedContainer>
#undef signals

#include "./suil_config.h"
#include "./suil_internal.h"

extern "C" {

static int
wrapper_wrap(SuilWrapper*  wrapper,
             SuilInstance* instance)
{
	QX11EmbedWidget* const    ew   = (QX11EmbedWidget*)wrapper->impl;
	QX11EmbedContainer* const wrap = new QX11EmbedContainer();

	ew->embedInto(wrap->winId());

	instance->host_widget = wrap;

	return 0;
}

static int
wrapper_resize(LV2UI_Feature_Handle handle, int width, int height)
{
	QX11EmbedWidget* const ew = (QX11EmbedWidget*)handle;
	ew->resize(width, height);
	return 0;
}

SUIL_API
SuilWrapper*
suil_wrapper_new(SuilHost*                 host,
                 const char*               host_type_uri,
                 const char*               ui_type_uri,
                 const LV2_Feature* const* features)
{
	SuilWrapper* wrapper = (SuilWrapper*)malloc(sizeof(SuilWrapper));
	wrapper->wrap = wrapper_wrap;
	wrapper->free = (SuilWrapperFreeFunc)free;

	unsigned n_features = 0;
	for (; features[n_features]; ++n_features) {}

	QX11EmbedWidget* const ew = new QX11EmbedWidget();
	wrapper->impl = ew;

	wrapper->features = (LV2_Feature**)malloc(
		sizeof(LV2_Feature*) * (n_features + 3));
	memcpy(wrapper->features, features, sizeof(LV2_Feature*) * n_features);

	LV2_Feature* parent_feature = (LV2_Feature*)malloc(sizeof(LV2_Feature));
	parent_feature->URI  = NS_UI "parent";
	parent_feature->data = (void*)(intptr_t)ew->winId();

	wrapper->features[n_features]     = parent_feature;
	wrapper->features[n_features + 1] = NULL;
	wrapper->features[n_features + 2] = NULL;

	wrapper->resize.handle    = ew;
	wrapper->resize.ui_resize = wrapper_resize;

	LV2_Feature* resize_feature = (LV2_Feature*)malloc(sizeof(LV2_Feature));
	resize_feature->URI  = LV2_UI__resize;
	resize_feature->data = &wrapper->resize;
	wrapper->features[n_features + 1] = resize_feature;

	return wrapper;
}

}  // extern "C"
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the CutePaste project
 * Copyright (c) 2013 Laszlo Papp <lpapp@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <QSslError>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTcpSocket>

#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
#include <QScopedPointer>
#include <QTextStream>
#include <QStringList>
#include <QCoreApplication>

int main(int argc, char **argv)
{
    QCoreApplication application(argc, argv);
    application.setOrganizationName("CutePaste");
    application.setApplicationName("CutePaste Desktop Console Frontend");

    QTextStream standardOutputStream(stdout);
    QNetworkRequest networkRequest;
    QFile dataFile;
    QString firstArgument = QCoreApplication::arguments().at(1);
    if (!firstArgument.isEmpty()) {
        dataFile.setFileName(firstArgument);
        dataFile.open(QIODevice::ReadOnly);
    } else {
        dataFile.open(stdin, QIODevice::ReadOnly);
    }

    QByteArray pasteTextByteArray = dataFile.readAll();

    QJsonDocument requestJsonDocument;
    QJsonObject requestJsonObject;

    requestJsonObject.insert(QStringLiteral("data"), QString(pasteTextByteArray));
    requestJsonObject.insert(QStringLiteral("language"), QStringLiteral("Text"));

    networkRequest.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
    networkRequest.setUrl(QUrl("http://sandbox.paste.kde.org/api/json/create"));

    QNetworkAccessManager networkAccessManager;
    QScopedPointer<QNetworkReply> networkReplyScopedPointer(networkAccessManager.post(networkRequest, &dataFile));
    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::finished, [&]() {
        QJsonDocument replyJsonDocument = QJsonDocument::fromJson(networkReplyScopedPointer->readAll());
        if (!replyJsonDocument.isObject())
            return;

        QJsonObject replyJsonObject = replyJsonDocument.object();
        QJsonValue identifierValue = replyJsonObject.value(QStringLiteral("id"));

        if (identifierValue.isString())
            endl(standardOutputStream << identifierValue.toString());
    });

    QObject::connect(networkReplyScopedPointer.data(), static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), [&](QNetworkReply::NetworkError networkReplyError) {
        if (networkReplyError != QNetworkReply::NoError)
            endl(standardOutputStream << networkReplyScopedPointer->errorString());
    });

    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::sslErrors, [&](QList<QSslError> networkReplySslErrors) {
        if (!networkReplySslErrors.isEmpty()) {
            foreach (const QSslError &networkReplySslError, networkReplySslErrors)
                endl(standardOutputStream << networkReplySslError.errorString());
        }
    });

    bool returnValue = application.exec();

    dataFile.close();
    if (dataFile.error() != QFileDevice::NoError)
        endl(standardOutputStream << dataFile.errorString());

    return returnValue;
}
<commit_msg>Fix the api url and set the header as well for the content type<commit_after>/******************************************************************************
 * This file is part of the CutePaste project
 * Copyright (c) 2013 Laszlo Papp <lpapp@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <QSslError>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTcpSocket>

#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
#include <QScopedPointer>
#include <QTextStream>
#include <QStringList>
#include <QCoreApplication>

int main(int argc, char **argv)
{
    QCoreApplication application(argc, argv);
    application.setOrganizationName("CutePaste");
    application.setApplicationName("CutePaste Desktop Console Frontend");

    QTextStream standardOutputStream(stdout);
    QFile dataFile;
    QString firstArgument = QCoreApplication::arguments().at(1);
    if (!firstArgument.isEmpty()) {
        dataFile.setFileName(firstArgument);
        dataFile.open(QIODevice::ReadOnly);
    } else {
        dataFile.open(stdin, QIODevice::ReadOnly);
    }

    QByteArray pasteTextByteArray = dataFile.readAll();

    QJsonDocument requestJsonDocument;
    QJsonObject requestJsonObject;

    requestJsonObject.insert(QStringLiteral("data"), QString::fromUtf8(pasteTextByteArray));
    requestJsonObject.insert(QStringLiteral("language"), QStringLiteral("Text"));

    QNetworkRequest networkRequest;
    networkRequest.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
    networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    networkRequest.setUrl(QUrl("http://sandbox.pastebin.kde.org/api/json/create"));

    QNetworkAccessManager networkAccessManager;
    QScopedPointer<QNetworkReply> networkReplyScopedPointer(networkAccessManager.post(networkRequest, &dataFile));
    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::finished, [&]() {
        QJsonDocument replyJsonDocument = QJsonDocument::fromJson(networkReplyScopedPointer->readAll());
        if (!replyJsonDocument.isObject())
            return;

        QJsonObject replyJsonObject = replyJsonDocument.object();
        QJsonValue identifierValue = replyJsonObject.value(QStringLiteral("id"));

        if (identifierValue.isString())
            endl(standardOutputStream << identifierValue.toString());
    });

    QObject::connect(networkReplyScopedPointer.data(), static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), [&](QNetworkReply::NetworkError networkReplyError) {
        if (networkReplyError != QNetworkReply::NoError)
            endl(standardOutputStream << networkReplyScopedPointer->errorString());
    });

    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::sslErrors, [&](QList<QSslError> networkReplySslErrors) {
        if (!networkReplySslErrors.isEmpty()) {
            foreach (const QSslError &networkReplySslError, networkReplySslErrors)
                endl(standardOutputStream << networkReplySslError.errorString());
        }
    });

    bool returnValue = application.exec();

    dataFile.close();
    if (dataFile.error() != QFileDevice::NoError)
        endl(standardOutputStream << dataFile.errorString());

    return returnValue;
}
<|endoftext|>