<commit_before>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "AnyImplsTest.h"

//--- test modules used --------------------------------------------------------
#include "TestSuite.h"

//--- module under test --------------------------------------------------------
#include "AnyImpls.h"

//--- standard modules used ----------------------------------------------------
#include "Dbg.h"

//--- c-modules used -----------------------------------------------------------

//---- AnyImplsTest ----------------------------------------------------------------
AnyImplsTest::AnyImplsTest(TString tstrName) : TestCaseType(tstrName)
{
	StartTrace(AnyImplsTest.Ctor);
}

AnyImplsTest::~AnyImplsTest()
{
	StartTrace(AnyImplsTest.Dtor);
}

void AnyImplsTest::DoubleToStringTest()
{
	StartTrace(AnyImplsTest.DoubleToStringTest);
	{
		String strBuf;
		double dValue = 1.0;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1", strBuf);
	}
	{
		String strBuf;
		double dValue = 1000000;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1000000", strBuf);
	}
	{
		String strBuf;
		double dValue = 1.23456789;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1.23456789", strBuf);
	}
	{
		String strBuf;
		double dValue = 0.0;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "0", strBuf);
	}
	{
		String strBuf;
		double dValue = 0.056;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "0.056", strBuf);
	}
	{
		// string will be cut 15 decimals after decimal point
		String strBuf;
		double dValue = (1.0 / 3.0);
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "0.333333333333333", strBuf);
	}
	{
		// string will be cut 15 decimals after decimal point
		String strBuf;
		double dValue = (100.0 / 3.0);
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "33.333333333333336", strBuf);
	}
	{
		// string will be cut 15 decimals after decimal point
		String strBuf;
		double dValue = 27.16;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "27.16", strBuf);
	}
	{
		String strBuf;
		double dValue = 1e15 + 0.123456789;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1000000000000000.125", strBuf);
	}
	{
		String strBuf;
		double dValue = 1e14 + 0.123456789;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "100000000000000.125", strBuf);
	}
	{
		String strBuf;
		double dValue = 1e12 + 0.123456789;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1000000000000.1234130859375", strBuf);
	}
	{
		String strBuf;
		double dValue = (1e+20) + 0.22134;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1e+20", strBuf);
	}
	{
		String strBuf;
		double dValue = 1e+30;
		AnyDoubleImpl::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1e+30", strBuf);
	}
}

// builds up a suite of testcases, add a line for each testmethod
Test *AnyImplsTest::suite ()
{
	StartTrace(AnyImplsTest.suite);
	TestSuite *testSuite = new TestSuite;

	ADD_CASE(testSuite, AnyImplsTest, DoubleToStringTest);

	return testSuite;
}
<commit_msg>adjusted tests to to moved DoubleToString conversion method<commit_after>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "AnyImplsTest.h"

//--- test modules used --------------------------------------------------------
#include "TestSuite.h"

//--- module under test --------------------------------------------------------
#include "AnyImpls.h"

//--- standard modules used ----------------------------------------------------
#include "Dbg.h"

//--- c-modules used -----------------------------------------------------------

//---- AnyImplsTest ----------------------------------------------------------------
AnyImplsTest::AnyImplsTest(TString tstrName) : TestCaseType(tstrName)
{
	StartTrace(AnyImplsTest.Ctor);
}

AnyImplsTest::~AnyImplsTest()
{
	StartTrace(AnyImplsTest.Dtor);
}

void AnyImplsTest::DoubleToStringTest()
{
	StartTrace(AnyImplsTest.DoubleToStringTest);
	{
		String strBuf;
		double dValue = 1.0;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1.0", strBuf);
	}
	{
		String strBuf;
		double dValue = 1000000;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1000000.0", strBuf);
	}
	{
		String strBuf;
		double dValue = 1.23456789;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1.23456789", strBuf);
	}
	{
		String strBuf;
		double dValue = 0.0;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "0.0", strBuf);
	}
	{
		String strBuf;
		double dValue = 0.056;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "0.056", strBuf);
	}
	{
		// string will be cut 15 decimals after decimal point
		String strBuf;
		double dValue = (1.0 / 3.0);
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "0.333333333333333", strBuf);
	}
	{
		// string will be cut 15 decimals after decimal point
		String strBuf;
		double dValue = (100.0 / 3.0);
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "33.333333333333336", strBuf);
	}
	{
		// string will be cut 15 decimals after decimal point
		String strBuf;
		double dValue = 27.16;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "27.16", strBuf);
	}
	{
		String strBuf;
		double dValue = 1e15 + 0.123456789;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1000000000000000.125", strBuf);
	}
	{
		String strBuf;
		double dValue = 1e14 + 0.123456789;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "100000000000000.125", strBuf);
	}
	{
		String strBuf;
		double dValue = 1e12 + 0.123456789;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1000000000000.1234130859375", strBuf);
	}
	{
		String strBuf;
		double dValue = (1e+20) + 0.22134;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1e+20", strBuf);
	}
	{
		String strBuf;
		double dValue = 1e+30;
		String::DoubleToString(dValue, strBuf);
		assertCharPtrEqual( "1e+30", strBuf);
	}
}

// builds up a suite of testcases, add a line for each testmethod
Test *AnyImplsTest::suite ()
{
	StartTrace(AnyImplsTest.suite);
	TestSuite *testSuite = new TestSuite;

	ADD_CASE(testSuite, AnyImplsTest, DoubleToStringTest);

	return testSuite;
}
<|endoftext|>


<commit_before>#include "videosourcefactory.h"
#include "videotargetfactory.h"
#include "except.h"
#include "iobservable.h"
#include "gil.h"
#ifdef USE_OPENCV
#include "opencv_video_source.h"
#include "opencv_video_target.h"
#endif // USE_OPENCV
#ifdef USE_EPIPHANSDK
#include "epiphansdk_video_source.h"
#endif
#ifdef USE_LIBVLC
#include "vlc_video_source.h"
#endif
#ifdef USE_FFMPEG
#include "ffmpeg_video_target.h"
#endif
#include <boost/python.hpp>
#include <boost/python/exception_translator.hpp>

using namespace boost::python;

class IObservableWrapper : public gg::IObservable, public wrapper<gg::IObservable>
{
public:
    void attach(gg::IObserver & observer)
    {
        if (override f = this->get_override("attach"))
            f(boost::ref(observer));
        else
            gg::IObservable::attach(boost::ref(observer));
    }

    void default_attach(gg::IObserver & observer)
    {
        gg::IObservable::attach(boost::ref(observer));
    }

    void detach(gg::IObserver & observer)
    {
        if (override f = this->get_override("detach"))
            f(boost::ref(observer));
        else
            gg::IObservable::detach(boost::ref(observer));
    }

    void default_detach(gg::IObserver & observer)
    {
        gg::IObservable::detach(boost::ref(observer));
    }
};

class IVideoSourceWrapper : public IVideoSource, public wrapper<IVideoSource>
{
public:
    bool get_frame_dimensions(int & width, int & height)
    {
        return this->get_override("get_frame_dimensions")(width, height);
    }

    bool get_frame(gg::VideoFrame & frame)
    {
        return this->get_override("get_frame")(frame);
    }

    double get_frame_rate()
    {
        return this->get_override("get_frame_rate")();
    }

    void set_sub_frame(int x, int y, int width, int height)
    {
        this->get_override("set_sub_frame")(x, y, width, height);
    }

    void get_full_frame()
    {
        this->get_override("get_full_frame")();
    }
};

/* The inheritance should be public, in order to preserve
 * the public accessibility of the update() method. The
 * Boost.Python examples feature struct's rather than
 * classes, and in struct's everything is public by
 * definition.
 */
class IObserverWrapper : public gg::IObserver, public wrapper<gg::IObserver>
{
public:
    IObserverWrapper()
    {
        /* Default constructor that needs to be called within
         * child Python class, e.g. super(Child, self).__init__()
         * This is normally generated by the compiler
         * automatically, but we define it here explicitly so
         * that it can serve as an example for this complex case.
         */
    }

    void update(gg::VideoFrame & frame)
    {
        gg::ScopedPythonGILLock gil_lock;
        this->get_override("update")(boost::ref(frame));
    }
};

class IVideoTargetWrapper : public gg::IVideoTarget, public wrapper<gg::IVideoTarget>
{
public:
    void append(const gg::VideoFrame & frame)
    {
        this->get_override("append")(frame);
    }
};

void translate_VideoSourceError(gg::VideoSourceError const & e)
{
    std::string msg;
    msg.append("VideoSourceError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

void translate_DeviceAlreadyConnected(gg::DeviceAlreadyConnected const & e)
{
    std::string msg;
    msg.append("DeviceAlreadyConnected: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_DeviceNotFound(gg::DeviceNotFound const & e)
{
    std::string msg;
    msg.append("DeviceNotFound: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_DeviceOffline(gg::DeviceOffline const & e)
{
    std::string msg;
    msg.append("DeviceOffline: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_VideoTargetError(gg::VideoTargetError const & e)
{
    std::string msg;
    msg.append("VideoTargetError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

void translate_ObserverError(gg::ObserverError const & e)
{
    std::string msg;
    msg.append("ObserverError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

BOOST_PYTHON_MODULE(pygiftgrab)
{
    PyEval_InitThreads();

    register_exception_translator<gg::VideoSourceError>(&translate_VideoSourceError);
    register_exception_translator<gg::DeviceAlreadyConnected>(&translate_DeviceAlreadyConnected);
    register_exception_translator<gg::DeviceNotFound>(&translate_DeviceNotFound);
    register_exception_translator<gg::DeviceOffline>(&translate_DeviceOffline);
    register_exception_translator<gg::VideoTargetError>(&translate_VideoTargetError);
    register_exception_translator<gg::ObserverError>(&translate_ObserverError);

    enum_<gg::ColourSpace>("ColourSpace")
        .value("BGRA", gg::ColourSpace::BGRA)
        .value("I420", gg::ColourSpace::I420)
    ;

    enum_<gg::Device>("Device")
        .value("DVI2PCIeDuo_SDI", gg::Device::DVI2PCIeDuo_SDI)
        .value("DVI2PCIeDuo_DVI", gg::Device::DVI2PCIeDuo_DVI)
    ;

    enum_<gg::Codec>("Codec")
        .value("HEVC", gg::Codec::HEVC)
        .value("Xvid", gg::Codec::Xvid)
        .value("VP9", gg::Codec::VP9)
    ;

    class_<gg::VideoFrame>("VideoFrame", init<enum gg::ColourSpace, bool>())
        .def(init<enum gg::ColourSpace, const size_t, const size_t>())
        .def("rows", &gg::VideoFrame::rows)
        .def("cols", &gg::VideoFrame::cols)
    ;

    class_<IObservableWrapper,boost::noncopyable>("IObservable", no_init)
        .def("attach", &IObservableWrapper::attach)
        .def("detach", &IObservableWrapper::detach)
    ;

    class_<IVideoSource, bases<gg::IObservable>, boost::noncopyable>(
                "IVideoSource", no_init)
    ;

#ifdef USE_OPENCV
    class_<VideoSourceOpenCV, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceOpenCV", init<int>())
        .def(init<char *>())
        .def("get_frame", &VideoSourceOpenCV::get_frame)
        .def("get_frame_dimensions", &VideoSourceOpenCV::get_frame_dimensions)
        .def("get_frame_rate", &VideoSourceOpenCV::get_frame_rate)
        .def("set_sub_frame", &VideoSourceOpenCV::set_sub_frame)
        .def("get_full_frame", &VideoSourceOpenCV::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif // USE_OPENCV

#ifdef USE_EPIPHANSDK
    class_<gg::VideoSourceEpiphanSDK, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceEpiphanSDK", init<const std::string, const V2U_INT32>())
        .def("get_frame", &gg::VideoSourceEpiphanSDK::get_frame)
        .def("get_frame_dimensions", &gg::VideoSourceEpiphanSDK::get_frame_dimensions)
        .def("get_frame_rate", &gg::VideoSourceEpiphanSDK::get_frame_rate)
        .def("set_sub_frame", &gg::VideoSourceEpiphanSDK::set_sub_frame)
        .def("get_full_frame", &gg::VideoSourceEpiphanSDK::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif

#ifdef USE_LIBVLC
    class_<gg::VideoSourceVLC, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceVLC", init<const std::string>())
        .def("get_frame", &gg::VideoSourceVLC::get_frame)
        .def("get_frame_dimensions", &gg::VideoSourceVLC::get_frame_dimensions)
        .def("get_frame_rate", &gg::VideoSourceVLC::get_frame_rate)
        .def("set_sub_frame", &gg::VideoSourceVLC::set_sub_frame)
        .def("get_full_frame", &gg::VideoSourceVLC::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif

    class_<IObserverWrapper, boost::noncopyable>("IObserver")
        .def("update", pure_virtual(&gg::IObserver::update))
    ;

    class_<gg::IVideoTarget, bases<gg::IObserver>, boost::noncopyable>(
                "IVideoTarget", no_init)
        .def("update", &gg::IVideoTarget::update)
    ;

#ifdef USE_FFMPEG
    class_<gg::VideoTargetFFmpeg, bases<gg::IVideoTarget>, boost::noncopyable>(
                "VideoTargetFFmpeg", init<std::string, std::string, float>())
        .def("append", &gg::VideoTargetFFmpeg::append)
    ;
#endif

#ifdef USE_OPENCV
    class_<gg::VideoTargetOpenCV, bases<gg::IVideoTarget>, boost::noncopyable>(
                "VideoTargetOpenCV", init<std::string, std::string, float>())
        .def("append", &gg::VideoTargetOpenCV::append)
    ;
#endif // USE_OPENCV

    class_<gg::VideoSourceFactory, boost::noncopyable>("VideoSourceFactory", no_init)
        .def("get_device", &gg::VideoSourceFactory::get_device
             /* Keep returned pointer (0) alive as long as factory (1) alive.
              * Boost.Python documentation says reference_existing_object is
              * dangerous, but apparently only when no additional lifetime
              * management with a call policy is provided (for details, see:
              * http://www.boost.org/doc/libs/1_39_0/libs/python/doc/v2/reference_existing_object.html
              * ).
              */
             , return_value_policy<reference_existing_object, with_custodian_and_ward_postcall<1, 0> >()
        )
        .def("free_device", &gg::VideoSourceFactory::free_device)
        .def("get_instance", &gg::VideoSourceFactory::get_instance
             , return_value_policy<reference_existing_object>()
        )
        .staticmethod("get_instance")
    ;

    class_<gg::VideoTargetFactory, boost::noncopyable>("VideoTargetFactory", no_init)
        .def("create_file_writer", &gg::VideoTargetFactory::create_file_writer,
             /* We use manage_new_object here in order
              * to give ownership is to client. Also
              * this ensures that the newly created
              * object will be destroyed as part of the
              * Python object destruction procedure. See
              * https://wiki.python.org/moin/boost.python/CallPolicy#manage_new_object
              */
             return_value_policy<manage_new_object>()
        )
        .def("get_instance", &gg::VideoTargetFactory::get_instance
             , return_value_policy<reference_existing_object>()
        )
        .staticmethod("get_instance")
    ;
}
<commit_msg>Issue #132: exposing VideoFrame data to NumPy<commit_after>#include "videosourcefactory.h"
#include "videotargetfactory.h"
#include "except.h"
#include "iobservable.h"
#include "gil.h"
#ifdef USE_OPENCV
#include "opencv_video_source.h"
#include "opencv_video_target.h"
#endif // USE_OPENCV
#ifdef USE_EPIPHANSDK
#include "epiphansdk_video_source.h"
#endif
#ifdef USE_LIBVLC
#include "vlc_video_source.h"
#endif
#ifdef USE_FFMPEG
#include "ffmpeg_video_target.h"
#endif
#include <boost/python.hpp>
#include <boost/python/exception_translator.hpp>
#ifdef USE_NUMPY
#include <boost/python/numpy.hpp>
#endif

using namespace boost::python;

#ifdef USE_NUMPY
class VideoFrameNumPyWrapper : public gg::VideoFrame, public wrapper<gg::VideoFrame>
{
public:
    //!
    //! \brief Create a NumPy array referencing gg::VideoFrame::data()
    //! \return
    //!
    boost::python::numpy::ndarray data_as_ndarray()
    {
        return boost::python::numpy::from_data(
                    this->data(),
                    boost::python::numpy::dtype::get_builtin<uint8_t>(),
                    // shape
                    boost::python::make_tuple(data_length()),
                    // stride, i.e. 1 byte to go to next entry in this case
                    boost::python::make_tuple(sizeof(uint8_t)),
                    // owner (dangerous to pass None)
                    boost::python::object()
               );
    }
};
#endif

class IObservableWrapper : public gg::IObservable, public wrapper<gg::IObservable>
{
public:
    void attach(gg::IObserver & observer)
    {
        if (override f = this->get_override("attach"))
            f(boost::ref(observer));
        else
            gg::IObservable::attach(boost::ref(observer));
    }

    void default_attach(gg::IObserver & observer)
    {
        gg::IObservable::attach(boost::ref(observer));
    }

    void detach(gg::IObserver & observer)
    {
        if (override f = this->get_override("detach"))
            f(boost::ref(observer));
        else
            gg::IObservable::detach(boost::ref(observer));
    }

    void default_detach(gg::IObserver & observer)
    {
        gg::IObservable::detach(boost::ref(observer));
    }
};

class IVideoSourceWrapper : public IVideoSource, public wrapper<IVideoSource>
{
public:
    bool get_frame_dimensions(int & width, int & height)
    {
        return this->get_override("get_frame_dimensions")(width, height);
    }

    bool get_frame(gg::VideoFrame & frame)
    {
        return this->get_override("get_frame")(frame);
    }

    double get_frame_rate()
    {
        return this->get_override("get_frame_rate")();
    }

    void set_sub_frame(int x, int y, int width, int height)
    {
        this->get_override("set_sub_frame")(x, y, width, height);
    }

    void get_full_frame()
    {
        this->get_override("get_full_frame")();
    }
};

/* The inheritance should be public, in order to preserve
 * the public accessibility of the update() method. The
 * Boost.Python examples feature struct's rather than
 * classes, and in struct's everything is public by
 * definition.
 */
class IObserverWrapper : public gg::IObserver, public wrapper<gg::IObserver>
{
public:
    IObserverWrapper()
    {
        /* Default constructor that needs to be called within
         * child Python class, e.g. super(Child, self).__init__()
         * This is normally generated by the compiler
         * automatically, but we define it here explicitly so
         * that it can serve as an example for this complex case.
         */
    }

    void update(gg::VideoFrame & frame)
    {
        gg::ScopedPythonGILLock gil_lock;
        this->get_override("update")(boost::ref(frame));
    }
};

class IVideoTargetWrapper : public gg::IVideoTarget, public wrapper<gg::IVideoTarget>
{
public:
    void append(const gg::VideoFrame & frame)
    {
        this->get_override("append")(frame);
    }
};

void translate_VideoSourceError(gg::VideoSourceError const & e)
{
    std::string msg;
    msg.append("VideoSourceError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

void translate_DeviceAlreadyConnected(gg::DeviceAlreadyConnected const & e)
{
    std::string msg;
    msg.append("DeviceAlreadyConnected: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_DeviceNotFound(gg::DeviceNotFound const & e)
{
    std::string msg;
    msg.append("DeviceNotFound: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_DeviceOffline(gg::DeviceOffline const & e)
{
    std::string msg;
    msg.append("DeviceOffline: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_VideoTargetError(gg::VideoTargetError const & e)
{
    std::string msg;
    msg.append("VideoTargetError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

void translate_ObserverError(gg::ObserverError const & e)
{
    std::string msg;
    msg.append("ObserverError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

BOOST_PYTHON_MODULE(pygiftgrab)
{
    PyEval_InitThreads();
#ifdef USE_NUMPY
    boost::python::numpy::initialize();
#endif

    register_exception_translator<gg::VideoSourceError>(&translate_VideoSourceError);
    register_exception_translator<gg::DeviceAlreadyConnected>(&translate_DeviceAlreadyConnected);
    register_exception_translator<gg::DeviceNotFound>(&translate_DeviceNotFound);
    register_exception_translator<gg::DeviceOffline>(&translate_DeviceOffline);
    register_exception_translator<gg::VideoTargetError>(&translate_VideoTargetError);
    register_exception_translator<gg::ObserverError>(&translate_ObserverError);

    enum_<gg::ColourSpace>("ColourSpace")
        .value("BGRA", gg::ColourSpace::BGRA)
        .value("I420", gg::ColourSpace::I420)
    ;

    enum_<gg::Device>("Device")
        .value("DVI2PCIeDuo_SDI", gg::Device::DVI2PCIeDuo_SDI)
        .value("DVI2PCIeDuo_DVI", gg::Device::DVI2PCIeDuo_DVI)
    ;

    enum_<gg::Codec>("Codec")
        .value("HEVC", gg::Codec::HEVC)
        .value("Xvid", gg::Codec::Xvid)
        .value("VP9", gg::Codec::VP9)
    ;

    class_<gg::VideoFrame>("VideoFrame", init<enum gg::ColourSpace, bool>())
        .def(init<enum gg::ColourSpace, const size_t, const size_t>())
        .def("rows", &gg::VideoFrame::rows)
        .def("cols", &gg::VideoFrame::cols)
#ifdef USE_NUMPY
        .def("data", &VideoFrameNumPyWrapper::data_as_ndarray)
#endif
    ;

    class_<IObservableWrapper,boost::noncopyable>("IObservable", no_init)
        .def("attach", &IObservableWrapper::attach)
        .def("detach", &IObservableWrapper::detach)
    ;

    class_<IVideoSource, bases<gg::IObservable>, boost::noncopyable>(
                "IVideoSource", no_init)
    ;

#ifdef USE_OPENCV
    class_<VideoSourceOpenCV, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceOpenCV", init<int>())
        .def(init<char *>())
        .def("get_frame", &VideoSourceOpenCV::get_frame)
        .def("get_frame_dimensions", &VideoSourceOpenCV::get_frame_dimensions)
        .def("get_frame_rate", &VideoSourceOpenCV::get_frame_rate)
        .def("set_sub_frame", &VideoSourceOpenCV::set_sub_frame)
        .def("get_full_frame", &VideoSourceOpenCV::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif // USE_OPENCV

#ifdef USE_EPIPHANSDK
    class_<gg::VideoSourceEpiphanSDK, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceEpiphanSDK", init<const std::string, const V2U_INT32>())
        .def("get_frame", &gg::VideoSourceEpiphanSDK::get_frame)
        .def("get_frame_dimensions", &gg::VideoSourceEpiphanSDK::get_frame_dimensions)
        .def("get_frame_rate", &gg::VideoSourceEpiphanSDK::get_frame_rate)
        .def("set_sub_frame", &gg::VideoSourceEpiphanSDK::set_sub_frame)
        .def("get_full_frame", &gg::VideoSourceEpiphanSDK::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif

#ifdef USE_LIBVLC
    class_<gg::VideoSourceVLC, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceVLC", init<const std::string>())
        .def("get_frame", &gg::VideoSourceVLC::get_frame)
        .def("get_frame_dimensions", &gg::VideoSourceVLC::get_frame_dimensions)
        .def("get_frame_rate", &gg::VideoSourceVLC::get_frame_rate)
        .def("set_sub_frame", &gg::VideoSourceVLC::set_sub_frame)
        .def("get_full_frame", &gg::VideoSourceVLC::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif

    class_<IObserverWrapper, boost::noncopyable>("IObserver")
        .def("update", pure_virtual(&gg::IObserver::update))
    ;

    class_<gg::IVideoTarget, bases<gg::IObserver>, boost::noncopyable>(
                "IVideoTarget", no_init)
        .def("update", &gg::IVideoTarget::update)
    ;

#ifdef USE_FFMPEG
    class_<gg::VideoTargetFFmpeg, bases<gg::IVideoTarget>, boost::noncopyable>(
                "VideoTargetFFmpeg", init<std::string, std::string, float>())
        .def("append", &gg::VideoTargetFFmpeg::append)
    ;
#endif

#ifdef USE_OPENCV
    class_<gg::VideoTargetOpenCV, bases<gg::IVideoTarget>, boost::noncopyable>(
                "VideoTargetOpenCV", init<std::string, std::string, float>())
        .def("append", &gg::VideoTargetOpenCV::append)
    ;
#endif // USE_OPENCV

    class_<gg::VideoSourceFactory, boost::noncopyable>("VideoSourceFactory", no_init)
        .def("get_device", &gg::VideoSourceFactory::get_device
             /* Keep returned pointer (0) alive as long as factory (1) alive.
              * Boost.Python documentation says reference_existing_object is
              * dangerous, but apparently only when no additional lifetime
              * management with a call policy is provided (for details, see:
              * http://www.boost.org/doc/libs/1_39_0/libs/python/doc/v2/reference_existing_object.html
              * ).
              */
             , return_value_policy<reference_existing_object, with_custodian_and_ward_postcall<1, 0> >()
        )
        .def("free_device", &gg::VideoSourceFactory::free_device)
        .def("get_instance", &gg::VideoSourceFactory::get_instance
             , return_value_policy<reference_existing_object>()
        )
        .staticmethod("get_instance")
    ;

    class_<gg::VideoTargetFactory, boost::noncopyable>("VideoTargetFactory", no_init)
        .def("create_file_writer", &gg::VideoTargetFactory::create_file_writer,
             /* We use manage_new_object here in order
              * to give ownership is to client. Also
              * this ensures that the newly created
              * object will be destroyed as part of the
              * Python object destruction procedure. See
              * https://wiki.python.org/moin/boost.python/CallPolicy#manage_new_object
              */
             return_value_policy<manage_new_object>()
        )
        .def("get_instance", &gg::VideoTargetFactory::get_instance
             , return_value_policy<reference_existing_object>()
        )
        .staticmethod("get_instance")
    ;
}
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkRoundRobinSchedulingAlgorithm.h"
#include "mitkSchedulableProcess.h"
#include "mitkScheduler.h"
#include "mitkWeightedRoundRobinSchedulingAlgorithm.h"
#include <algorithm>
#include <cassert>
#include <vector>

struct mitk::Scheduler::Impl
{
  std::vector<SchedulableProcess*> processQueue;
  SchedulingAlgorithmBase* algorithm;
};

mitk::Scheduler::Scheduler(SchedulingAlgorithm::Enum algorithm)
  : m_Impl(new Impl)
{
  switch (algorithm)
  {
  case mitk::SchedulingAlgorithm::RoundRobin:
    m_Impl->algorithm = new mitk::RoundRobinSchedulingAlgorithm;

  case mitk::SchedulingAlgorithm::WeightedRoundRobin:
    m_Impl->algorithm = new mitk::WeightedRoundRobinSchedulingAlgorithm;

  default:
    assert(false);
  }
}

mitk::Scheduler::~Scheduler()
{
  delete m_Impl->algorithm;
  delete m_Impl;
}

void mitk::Scheduler::AddProcess(SchedulableProcess* process)
{
  if (process == NULL)
    return;

  if (std::find(m_Impl->processQueue.begin(), m_Impl->processQueue.end(), process) == m_Impl->processQueue.end())
    m_Impl->processQueue.push_back(process);
}

void mitk::Scheduler::RemoveProcess(SchedulableProcess* process)
{
  if (process == NULL)
    return;

  std::vector<SchedulableProcess*>::iterator it = std::find(m_Impl->processQueue.begin(), m_Impl->processQueue.end(), process);

  if (it != m_Impl->processQueue.end())
    m_Impl->processQueue.erase(it);
}

bool mitk::Scheduler::IsEmpty() const
{
  return m_Impl->processQueue.empty();
}

mitk::SchedulableProcess* mitk::Scheduler::GetCurrentProcess()
{
  return !m_Impl->processQueue.empty()
    ? m_Impl->processQueue[0]
    : NULL;
}

mitk::SchedulableProcess* mitk::Scheduler::GetNextProcess()
{
  return m_Impl->algorithm->GetNextProcess(m_Impl->processQueue);
}
<commit_msg>Added missing breaks in switch statement.<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkRoundRobinSchedulingAlgorithm.h"
#include "mitkSchedulableProcess.h"
#include "mitkScheduler.h"
#include "mitkWeightedRoundRobinSchedulingAlgorithm.h"
#include <algorithm>
#include <cassert>
#include <vector>

struct mitk::Scheduler::Impl
{
  std::vector<SchedulableProcess*> processQueue;
  SchedulingAlgorithmBase* algorithm;
};

mitk::Scheduler::Scheduler(SchedulingAlgorithm::Enum algorithm)
  : m_Impl(new Impl)
{
  switch (algorithm)
  {
  case mitk::SchedulingAlgorithm::RoundRobin:
    m_Impl->algorithm = new mitk::RoundRobinSchedulingAlgorithm;
    break;

  case mitk::SchedulingAlgorithm::WeightedRoundRobin:
    m_Impl->algorithm = new mitk::WeightedRoundRobinSchedulingAlgorithm;
    break;

  default:
    assert(false && "Unknown scheduling algorithm!");
  }
}

mitk::Scheduler::~Scheduler()
{
  delete m_Impl->algorithm;
  delete m_Impl;
}

void mitk::Scheduler::AddProcess(SchedulableProcess* process)
{
  if (process == NULL)
    return;

  if (std::find(m_Impl->processQueue.begin(), m_Impl->processQueue.end(), process) == m_Impl->processQueue.end())
    m_Impl->processQueue.push_back(process);
}

void mitk::Scheduler::RemoveProcess(SchedulableProcess* process)
{
  if (process == NULL)
    return;

  std::vector<SchedulableProcess*>::iterator it = std::find(m_Impl->processQueue.begin(), m_Impl->processQueue.end(), process);

  if (it != m_Impl->processQueue.end())
    m_Impl->processQueue.erase(it);
}

bool mitk::Scheduler::IsEmpty() const
{
  return m_Impl->processQueue.empty();
}

mitk::SchedulableProcess* mitk::Scheduler::GetCurrentProcess()
{
  return !m_Impl->processQueue.empty()
    ? m_Impl->processQueue[0]
    : NULL;
}

mitk::SchedulableProcess* mitk::Scheduler::GetNextProcess()
{
  return m_Impl->algorithm->GetNextProcess(m_Impl->processQueue);
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

/* system headers */
#include <sstream>
#include <string>
#include <stdio.h>
#include <string.h>

// opaque version number increments on protocol incompatibility
#ifndef BZ_PROTO_VERSION
#  define BZ_PROTO_VERSION	"0026"
#endif

// version numbers - also update:
//  ChangeLog
//  README
//  package/win32/nsis/*.nsi
//  package/win32/*.nsi
//  tools/TextTool-W32/TextTool.rc
//  win32/VC6/installer.dsp
#ifndef BZ_MAJOR_VERSION
#  define BZ_MAJOR_VERSION	2
#endif

#ifndef BZ_MINOR_VERSION
#  define BZ_MINOR_VERSION	0
#endif

#ifndef BZ_REV
#  define BZ_REV		5
#endif

// DEVEL | STABLE | MAINT
#ifndef BZ_BUILD_TYPE
#  define BZ_BUILD_TYPE		"DEVEL"
#endif

const char *bzfcopyright = "Copyright (c) 1993 - 2005 Tim Riker";

//
//  Although the ./configure process will generate
//  -DBZ_BUILD_DATE for the build, here it's voided.
//
//  Could someone explain the reason for the
//  inconience caused by the ./configure method? This
//  way is simple, touch the *.cxx to get a new time
//  stamp (no big recompiles). If this file is updated,
//  you are also forced to get a new timestamp.
//
//  Using __DATE__ for all OSes is more consistent.
//
#undef BZ_BUILD_DATE

#ifndef BZ_BUILD_DATE
/* to get the version in the right format YYYYMMDD */
/* yes this is horible but it needs to be done to get it right */
/* windows should pull from a resouce */
/* *nix gets this from the passed from my the Makefile */
char buildDate[] = {__DATE__};

int getBuildDate()
{
  int year = 1900, month = 0, day = 0;
  char monthStr[512];
  sscanf(buildDate, "%s %d %d", monthStr, &day, &year);

  // we want it not as a name but a number
  if (strcmp(monthStr, "Jan") == 0)
    month = 1;
  else if (strcmp(monthStr, "Feb") == 0)
    month = 2;
  else if (strcmp(monthStr, "Mar") == 0)
    month = 3;
  else if (strcmp(monthStr, "Apr") == 0)
    month = 4;
  else if (strcmp(monthStr, "May") == 0)
    month = 5;
  else if (strcmp(monthStr, "Jun") == 0)
    month = 6;
  else if (strcmp(monthStr, "Jul") == 0)
    month = 7;
  else if (strcmp(monthStr, "Aug") == 0)
    month = 8;
  else if (strcmp(monthStr, "Sep") == 0)
    month = 9;
  else if (strcmp(monthStr, "Oct") == 0)
    month = 10;
  else if (strcmp(monthStr, "Nov") == 0)
    month = 11;
  else if (strcmp(monthStr, "Dec") == 0)
    month = 12;

  return (year*10000) + (month*100)+ day;
}
#endif
// down here so above gets created
#include "version.h"

const char*		getProtocolVersion()
{
  static std::string protVersion = BZ_PROTO_VERSION;
  return protVersion.c_str();
}

const char*		getServerVersion()
{
  static std::string serverVersion = std::string("BZFS") + getProtocolVersion();
  return serverVersion.c_str();
}

const char*		getMajorMinorVersion()
{
  static std::string	version = "";
  if (!version.size()){
    std::ostringstream	versionStream;
    versionStream << BZ_MAJOR_VERSION << "." << BZ_MINOR_VERSION;
    version = versionStream.str();
  }
  return version.c_str();
}

const char*		getMajorMinorRevVersion()
{
  static std::string	version = "";
  if (!version.size()){
    std::ostringstream	versionStream;
    versionStream << BZ_MAJOR_VERSION << "." << BZ_MINOR_VERSION << "." << BZ_REV;
    version = versionStream.str();
  }
  return version.c_str();
}

const char*		getAppVersion()
{
  static std::string	appVersion = "";
  if (!appVersion.size()){
    std::ostringstream	appVersionStream;
    // TODO add current platform, release, cpu, etc
    appVersionStream << getMajorMinorRevVersion() << "." << BZ_BUILD_DATE
	<< "-" << BZ_BUILD_TYPE << "-" << BZ_BUILD_OS;
#ifdef HAVE_SDL
    appVersionStream << "-SDL";
#endif
    appVersion = appVersionStream.str();
  }
  return appVersion.c_str();
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Birth of a new age<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

/* system headers */
#include <sstream>
#include <string>
#include <stdio.h>
#include <string.h>

// opaque version number increments on protocol incompatibility
#ifndef BZ_PROTO_VERSION
#  define BZ_PROTO_VERSION	"0026"
#endif

// version numbers - also update:
//  ChangeLog
//  README
//  package/win32/nsis/*.nsi
//  package/win32/*.nsi
//  tools/TextTool-W32/TextTool.rc
//  win32/VC6/installer.dsp
#ifndef BZ_MAJOR_VERSION
#  define BZ_MAJOR_VERSION	2
#endif

#ifndef BZ_MINOR_VERSION
#  define BZ_MINOR_VERSION	1
#endif

#ifndef BZ_REV
#  define BZ_REV		0
#endif

// DEVEL | STABLE | MAINT
#ifndef BZ_BUILD_TYPE
#  define BZ_BUILD_TYPE		"DEVEL"
#endif

const char *bzfcopyright = "Copyright (c) 1993 - 2005 Tim Riker";

//
//  Although the ./configure process will generate
//  -DBZ_BUILD_DATE for the build, here it's voided.
//
//  Could someone explain the reason for the
//  inconience caused by the ./configure method? This
//  way is simple, touch the *.cxx to get a new time
//  stamp (no big recompiles). If this file is updated,
//  you are also forced to get a new timestamp.
//
//  Using __DATE__ for all OSes is more consistent.
//
#undef BZ_BUILD_DATE

#ifndef BZ_BUILD_DATE
/* to get the version in the right format YYYYMMDD */
/* yes this is horible but it needs to be done to get it right */
/* windows should pull from a resouce */
/* *nix gets this from the passed from my the Makefile */
char buildDate[] = {__DATE__};

int getBuildDate()
{
  int year = 1900, month = 0, day = 0;
  char monthStr[512];
  sscanf(buildDate, "%s %d %d", monthStr, &day, &year);

  // we want it not as a name but a number
  if (strcmp(monthStr, "Jan") == 0)
    month = 1;
  else if (strcmp(monthStr, "Feb") == 0)
    month = 2;
  else if (strcmp(monthStr, "Mar") == 0)
    month = 3;
  else if (strcmp(monthStr, "Apr") == 0)
    month = 4;
  else if (strcmp(monthStr, "May") == 0)
    month = 5;
  else if (strcmp(monthStr, "Jun") == 0)
    month = 6;
  else if (strcmp(monthStr, "Jul") == 0)
    month = 7;
  else if (strcmp(monthStr, "Aug") == 0)
    month = 8;
  else if (strcmp(monthStr, "Sep") == 0)
    month = 9;
  else if (strcmp(monthStr, "Oct") == 0)
    month = 10;
  else if (strcmp(monthStr, "Nov") == 0)
    month = 11;
  else if (strcmp(monthStr, "Dec") == 0)
    month = 12;

  return (year*10000) + (month*100)+ day;
}
#endif
// down here so above gets created
#include "version.h"

const char*		getProtocolVersion()
{
  static std::string protVersion = BZ_PROTO_VERSION;
  return protVersion.c_str();
}

const char*		getServerVersion()
{
  static std::string serverVersion = std::string("BZFS") + getProtocolVersion();
  return serverVersion.c_str();
}

const char*		getMajorMinorVersion()
{
  static std::string	version = "";
  if (!version.size()){
    std::ostringstream	versionStream;
    versionStream << BZ_MAJOR_VERSION << "." << BZ_MINOR_VERSION;
    version = versionStream.str();
  }
  return version.c_str();
}

const char*		getMajorMinorRevVersion()
{
  static std::string	version = "";
  if (!version.size()){
    std::ostringstream	versionStream;
    versionStream << BZ_MAJOR_VERSION << "." << BZ_MINOR_VERSION << "." << BZ_REV;
    version = versionStream.str();
  }
  return version.c_str();
}

const char*		getAppVersion()
{
  static std::string	appVersion = "";
  if (!appVersion.size()){
    std::ostringstream	appVersionStream;
    // TODO add current platform, release, cpu, etc
    appVersionStream << getMajorMinorRevVersion() << "." << BZ_BUILD_DATE
	<< "-" << BZ_BUILD_TYPE << "-" << BZ_BUILD_OS;
#ifdef HAVE_SDL
    appVersionStream << "-SDL";
#endif
    appVersion = appVersionStream.str();
  }
  return appVersion.c_str();
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>// http://msdn.microsoft.com/en-us/library/aa365968(VS.85).aspx
// Link with IPHlpAPI.lib

#include <winsock2.h>
#include <iphlpapi.h>
#include <stdlib.h>
#include <windows.h>

#include <string>
#include <vector>

namespace urpc {
namespace dns {

void getDNSServer(std::vector<std::string> &server)
{
  FIXED_INFO *pFixedInfo;
  ULONG ulOutBufLen;
  IP_ADDR_STRING *pIPAddr;

  pFixedInfo = (FIXED_INFO *) malloc(sizeof (FIXED_INFO));
  ulOutBufLen = sizeof (FIXED_INFO);

  // get the size of pFixedInfo
  GetNetworkParams(pFixedInfo, &ulOutBufLen);
  free(pFixedInfo);

  // get actual data
  pFixedInfo = (FIXED_INFO *) malloc(ulOutBufLen);
  GetNetworkParams(pFixedInfo, &ulOutBufLen);

  server.push_back(pFixedInfo->DnsServerList.IpAddress.String);
  pIPAddr = pFixedInfo->DnsServerList.Next;
  while (pIPAddr)
  {
    server.push_back(pIPAddr->IpAddress.String);
    pIPAddr = pIPAddr->Next;
  }
  free(pFixedInfo);
}

}
}
<commit_msg>simplified entry to getServer<commit_after>// http://msdn.microsoft.com/en-us/library/aa365968(VS.85).aspx
// Link with IPHlpAPI.lib

#include <winsock2.h>
#include <iphlpapi.h>
#include <stdlib.h>
#include <windows.h>

#include <string>
#include <vector>

namespace urpc {
namespace dns {

void getServer(std::vector<std::string> &server)
{
  FIXED_INFO *pFixedInfo;
  ULONG ulOutBufLen;
  IP_ADDR_STRING *pIPAddr;

  pFixedInfo = (FIXED_INFO *) malloc(sizeof (FIXED_INFO));
  ulOutBufLen = sizeof (FIXED_INFO);

  // get the size of pFixedInfo
  GetNetworkParams(pFixedInfo, &ulOutBufLen);
  free(pFixedInfo);

  // get actual data
  pFixedInfo = (FIXED_INFO *) malloc(ulOutBufLen);
  GetNetworkParams(pFixedInfo, &ulOutBufLen);

  server.push_back(pFixedInfo->DnsServerList.IpAddress.String);
  pIPAddr = pFixedInfo->DnsServerList.Next;
  while (pIPAddr)
  {
    server.push_back(pIPAddr->IpAddress.String);
    pIPAddr = pIPAddr->Next;
  }
  free(pFixedInfo);
}

}
}
<|endoftext|>


<commit_before><commit_msg>test congestion thresh back to 0.6<commit_after><|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "FBO.h"

#include "OGLHelper.h"
#include "GLContext.h"
#include "Filterfliprgb.h"

#include "../base/Exception.h"
#include "../base/StringHelper.h"
#include "../base/ObjectCounter.h"

#include <stdio.h>

using namespace std;
using namespace boost;

namespace avg {

#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
#endif

#ifdef AVG_ENABLE_EGL
#define GL_DEPTH_STENCIL_EXT GL_DEPTH24_STENCIL8_OES
#endif

FBO::FBO(const IntPoint& size, PixelFormat pf, unsigned numTextures,
        unsigned multisampleSamples, bool bUsePackedDepthStencil, bool bMipmap)
    : m_Size(size),
      m_PF(pf),
      m_MultisampleSamples(multisampleSamples),
      m_bUsePackedDepthStencil(bUsePackedDepthStencil),
      m_bMipmap(bMipmap)
{
    ObjectCounter::get()->incRef(&typeid(*this));
    AVG_ASSERT(numTextures == 1 || multisampleSamples == 1);
    if (multisampleSamples > 1 && !(isMultisampleFBOSupported())) {
        throw Exception(AVG_ERR_UNSUPPORTED,
                "Multisample offscreen rendering is not supported by this OpenGL driver/card combination.");
    }

    for (unsigned i=0; i<numTextures; ++i) {
        GLTexturePtr pTex = GLTexturePtr(new GLTexture(size, pf, bMipmap));
        // Workaround for NVidia driver bug - GL_TEX_MIN_FILTER without
        // glGenerateMipmaps causes FBO creation to fail(?!).
        pTex->generateMipmaps();
        m_pTextures.push_back(pTex);
    }
    init();
}

FBO::~FBO()
{
    ObjectCounter::get()->decRef(&typeid(*this));

    unsigned oldFBOID;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&oldFBOID);
    glproc::BindFramebuffer(GL_FRAMEBUFFER, m_FBO);

    for (unsigned i=0; i<m_pTextures.size(); ++i) {
        glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i,
                GL_TEXTURE_2D, 0, 0);
    }

    GLContext* pContext = GLContext::getCurrent();
    if (pContext) {
        pContext->returnFBOToCache(m_FBO);
        if (m_MultisampleSamples > 1) {
            glproc::DeleteRenderbuffers(1, &m_ColorBuffer);
            pContext->returnFBOToCache(m_OutputFBO);
        }
        if (m_bUsePackedDepthStencil && isPackedDepthStencilSupported()) {
            glproc::DeleteRenderbuffers(1, &m_StencilBuffer);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                    GL_RENDERBUFFER, 0);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                    GL_RENDERBUFFER, 0);
            if (m_MultisampleSamples > 1) {
                glproc::BindFramebuffer(GL_FRAMEBUFFER, m_OutputFBO);
                glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                        GL_TEXTURE_2D, 0, 0);
            }
        }
        glproc::BindFramebuffer(GL_FRAMEBUFFER, oldFBOID);
        GLContext::checkError("~FBO");
    }
}

void FBO::activate() const
{
    glproc::BindFramebuffer(GL_FRAMEBUFFER, m_FBO);
    GLContext::checkError("FBO::activate: BindFramebuffer()");
    checkError("activate");
}

PixelFormat FBO::getPF() const
{
    return m_PF;
}

unsigned FBO::getNumTextures() const
{
    return m_pTextures.size();
}

void FBO::copyToDestTexture() const
{
#ifndef AVG_ENABLE_EGL
    if (m_MultisampleSamples != 1) {
        // Copy Multisample FBO to destination fbo
        glproc::BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_FBO);
        glproc::BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_OutputFBO);
        glproc::BlitFramebuffer(0, 0, m_Size.x, m_Size.y, 0, 0, m_Size.x, m_Size.y,
                GL_COLOR_BUFFER_BIT, GL_LINEAR);
        glproc::BindFramebuffer(GL_FRAMEBUFFER, 0);
    }
#endif
    if (m_bMipmap) {
        for (unsigned i=0; i< m_pTextures.size(); ++i) {
            m_pTextures[i]->generateMipmaps();
        }
    }
}

BitmapPtr FBO::getImage(int i) const
{
    GLContext* pContext = GLContext::getCurrent();
    if (pContext->getMemoryMode() == MM_PBO) {
        moveToPBO(i);
        return getImageFromPBO();
    } else {
        BitmapPtr pBmp(new Bitmap(m_Size, m_PF));
        glproc::BindFramebuffer(GL_FRAMEBUFFER, m_OutputFBO);
        glReadPixels(0, 0, m_Size.x, m_Size.y, GLTexture::getGLReadFormat(m_PF),
                GLTexture::getGLType(m_PF), pBmp->getPixels());
        if (pContext->isGLES()) {
            FilterFlipRGB(!pContext->isGLES()).applyInPlace(pBmp);
        }
        GLContext::checkError("FBO::getImage ReadPixels()");
        return pBmp;
    }
}

void FBO::moveToPBO(int i) const
{
    AVG_ASSERT(GLContext::getCurrent()->getMemoryMode() == MM_PBO);
#ifndef AVG_ENABLE_EGL
    // Get data directly from the FBO using glReadBuffer. At least on NVidia/Linux, this
    // is faster than reading stuff from the texture.
    copyToDestTexture();
    glproc::BindFramebuffer(GL_FRAMEBUFFER, m_OutputFBO);

    m_pOutputPBO->activate();
    GLContext::checkError("FBO::moveToPBO BindBuffer()");
    glReadBuffer(GL_COLOR_ATTACHMENT0+i);
    GLContext::checkError("FBO::moveToPBO ReadBuffer()");

    glReadPixels(0, 0, m_Size.x, m_Size.y, GLTexture::getGLFormat(m_PF),
            GLTexture::getGLType(m_PF), 0);
    GLContext::checkError("FBO::moveToPBO ReadPixels()");
#endif
}

BitmapPtr FBO::getImageFromPBO() const
{
#ifdef AVG_ENABLE_EGL
    AVG_ASSERT(false);
    return BitmapPtr();
#else
    AVG_ASSERT(GLContext::getCurrent()->getMemoryMode() == MM_PBO);
    m_pOutputPBO->activate();
    GLContext::checkError("FBO::getImageFromPBO BindBuffer()");

    BitmapPtr pBmp(new Bitmap(m_Size, m_PF));
    void * pPBOPixels = glproc::MapBuffer(GL_PIXEL_PACK_BUFFER_EXT, GL_READ_ONLY);
    GLContext::checkError("FBO::getImageFromPBO MapBuffer()");
    Bitmap PBOBitmap(m_Size, m_PF, (unsigned char *)pPBOPixels,
            m_Size.x*getBytesPerPixel(m_PF), false);
    pBmp->copyPixels(PBOBitmap);
    glproc::UnmapBuffer(GL_PIXEL_PACK_BUFFER_EXT);
    GLContext::checkError("FBO::getImageFromPBO UnmapBuffer()");
    return pBmp;
#endif
}

GLTexturePtr FBO::getTex(int i) const
{
    return m_pTextures[i];
}

const IntPoint& FBO::getSize() const
{
    return m_Size;
}

unsigned FBO::getID() const
{
    return m_FBO;
}

void FBO::init()
{
    GLContext* pContext = GLContext::getCurrent();
    if (m_bUsePackedDepthStencil && !isPackedDepthStencilSupported()) {
        throw Exception(AVG_ERR_UNSUPPORTED, "OpenGL implementation does not support offscreen cropping (GL_EXT_packed_depth_stencil).");
    }
    if (m_MultisampleSamples > 1 && !isMultisampleFBOSupported()) {
        throw Exception(AVG_ERR_UNSUPPORTED, "OpenGL implementation does not support multisample offscreen rendering (GL_EXT_framebuffer_multisample).");
    }
#ifndef AVG_ENABLE_EGL
    if (GLContext::getCurrent()->getMemoryMode() == MM_PBO) {
        m_pOutputPBO = PBOPtr(new PBO(m_Size, m_PF, GL_STREAM_READ));
    }
#endif

    m_FBO = pContext->genFBO();
    GLContext::checkError("FBO::init: GenFramebuffers()");

    glproc::BindFramebuffer(GL_FRAMEBUFFER, m_FBO);
    GLContext::checkError("FBO::init: BindFramebuffer()");

    if (m_MultisampleSamples == 1) {
        for (unsigned i=0; i<m_pTextures.size(); ++i) {
            glproc::FramebufferTexture2D(GL_FRAMEBUFFER,
                    GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D,
                    m_pTextures[i]->getID(), 0);
            GLContext::checkError("FBO: glFramebufferTexture2D()");
        }
        if (m_bUsePackedDepthStencil) {
            glproc::GenRenderbuffers(1, &m_StencilBuffer);
            glproc::BindRenderbuffer(GL_RENDERBUFFER, m_StencilBuffer);
            glproc::RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL_EXT,
                    m_Size.x, m_Size.y);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                    GL_RENDERBUFFER, m_StencilBuffer);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                    GL_RENDERBUFFER, m_StencilBuffer);
            GLContext::checkError("FBO::init: FramebufferRenderbuffer(STENCIL)");
        }
        m_OutputFBO = m_FBO;
    } else {
#ifdef AVG_ENABLE_EGL
        AVG_ASSERT(false);
#else
        glproc::GenRenderbuffers(1, &m_ColorBuffer);
        glproc::BindRenderbuffer(GL_RENDERBUFFER, m_ColorBuffer);
        GLContext::enableErrorLog(false);
        glproc::RenderbufferStorageMultisample(GL_RENDERBUFFER, m_MultisampleSamples,
                GL_RGBA8, m_Size.x, m_Size.y);
        GLContext::enableErrorLog(true);
        GLenum err = glGetError();
        if (err == GL_INVALID_VALUE) {
            glproc::BindFramebuffer(GL_FRAMEBUFFER, 0);
            glproc::DeleteFramebuffers(1, &m_FBO);
            glproc::DeleteRenderbuffers(1, &m_ColorBuffer);
            m_pOutputPBO = PBOPtr();
            throw(Exception(AVG_ERR_UNSUPPORTED,
                    string("Unsupported value for number of multisample samples (")
                    + toString(m_MultisampleSamples) + ")."));
        }
        GLContext::checkError("FBO::init: RenderbufferStorageMultisample");
        glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_RENDERBUFFER, m_ColorBuffer);
        GLContext::checkError("FBO::init: FramebufferRenderbuffer");
        if (m_bUsePackedDepthStencil) {
            glproc::GenRenderbuffers(1, &m_StencilBuffer);
            glproc::BindRenderbuffer(GL_RENDERBUFFER, m_StencilBuffer);
            glproc::RenderbufferStorageMultisample(GL_RENDERBUFFER,
                    m_MultisampleSamples, GL_DEPTH_STENCIL_EXT, m_Size.x, m_Size.y);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                    GL_RENDERBUFFER, m_StencilBuffer);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                    GL_RENDERBUFFER, m_StencilBuffer);
            GLContext::checkError("FBO::init: FramebufferRenderbuffer(STENCIL)");
        }
        checkError("init multisample");
        m_OutputFBO = pContext->genFBO();
        glproc::BindFramebuffer(GL_FRAMEBUFFER, m_OutputFBO);
        glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D, m_pTextures[0]->getID(), 0);

        GLContext::checkError("FBO::init: Multisample init");
#endif
    }

    checkError("init");
    glproc::BindFramebuffer(GL_FRAMEBUFFER, 0);
}

bool FBO::isFBOSupported()
{
    return queryOGLExtension("GL_EXT_framebuffer_object");
}

bool FBO::isMultisampleFBOSupported()
{
#ifdef AVG_ENABLE_EGL
    return false;
#else
    int maxSamples;
    glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
    // For some reason, this fails on Linux/i945 and similar setups. Multisample
    // FBO is broken anyway on these machines, so we just return false...
    GLenum err = glGetError();
    if (err != GL_NO_ERROR) {
        return false;
    }
    return queryOGLExtension("GL_EXT_framebuffer_multisample") &&
            queryOGLExtension("GL_EXT_framebuffer_blit") && maxSamples > 1;
#endif
}

bool FBO::isPackedDepthStencilSupported()
{
    return queryOGLExtension("GL_EXT_packed_depth_stencil") ||
            queryOGLExtension("GL_OES_packed_depth_stencil");
}

void FBO::checkError(const string& sContext)
{
    GLenum status = glproc::CheckFramebufferStatus(GL_FRAMEBUFFER);
    string sErr;
    switch (status) {
        case GL_FRAMEBUFFER_COMPLETE:
            return;
        case GL_FRAMEBUFFER_UNSUPPORTED:
            sErr = "GL_FRAMEBUFFER_UNSUPPORTED";
            throw Exception(AVG_ERR_UNSUPPORTED, string("Framebuffer error: ")+sErr);
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            sErr = "GL_INCOMPLETE_ATTACHMENT";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
            break;
#ifndef AVG_ENABLE_EGL
        case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT";
            break;
        case GL_FRAMEBUFFER_BINDING_EXT:
            sErr = "GL_FRAMEBUFFER_BINDING_EXT";
            break;
#endif
        default:
            sErr = "Unknown error";
            break;
    }
    cerr << "Framebuffer error (" << sContext << "): " << sErr << endl;
    AVG_ASSERT(false);
}

}

<commit_msg>egl branch: Working offscreen rendering.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "FBO.h"

#include "OGLHelper.h"
#include "GLContext.h"
#include "Filterfliprgb.h"

#include "../base/Exception.h"
#include "../base/StringHelper.h"
#include "../base/ObjectCounter.h"

#include <stdio.h>

using namespace std;
using namespace boost;

namespace avg {

#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
#endif

#ifdef AVG_ENABLE_EGL
#define GL_DEPTH_STENCIL_EXT GL_DEPTH24_STENCIL8_OES
#endif

FBO::FBO(const IntPoint& size, PixelFormat pf, unsigned numTextures,
        unsigned multisampleSamples, bool bUsePackedDepthStencil, bool bMipmap)
    : m_Size(size),
      m_PF(pf),
      m_MultisampleSamples(multisampleSamples),
      m_bUsePackedDepthStencil(bUsePackedDepthStencil),
      m_bMipmap(bMipmap)
{
    ObjectCounter::get()->incRef(&typeid(*this));
    AVG_ASSERT(numTextures == 1 || multisampleSamples == 1);
    if (multisampleSamples > 1 && !(isMultisampleFBOSupported())) {
        throw Exception(AVG_ERR_UNSUPPORTED,
                "Multisample offscreen rendering is not supported by this OpenGL driver/card combination.");
    }

    for (unsigned i=0; i<numTextures; ++i) {
        GLTexturePtr pTex = GLTexturePtr(new GLTexture(size, pf, bMipmap));
        // Workaround for NVidia driver bug - GL_TEX_MIN_FILTER without
        // glGenerateMipmaps causes FBO creation to fail(?!).
        pTex->generateMipmaps();
        m_pTextures.push_back(pTex);
    }
    init();
}

FBO::~FBO()
{
    ObjectCounter::get()->decRef(&typeid(*this));

    unsigned oldFBOID;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&oldFBOID);
    glproc::BindFramebuffer(GL_FRAMEBUFFER, m_FBO);

    for (unsigned i=0; i<m_pTextures.size(); ++i) {
        glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i,
                GL_TEXTURE_2D, 0, 0);
    }

    GLContext* pContext = GLContext::getCurrent();
    if (pContext) {
        pContext->returnFBOToCache(m_FBO);
        if (m_MultisampleSamples > 1) {
            glproc::DeleteRenderbuffers(1, &m_ColorBuffer);
            pContext->returnFBOToCache(m_OutputFBO);
        }
        if (m_bUsePackedDepthStencil && isPackedDepthStencilSupported()) {
            glproc::DeleteRenderbuffers(1, &m_StencilBuffer);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                    GL_RENDERBUFFER, 0);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                    GL_RENDERBUFFER, 0);
            if (m_MultisampleSamples > 1) {
                glproc::BindFramebuffer(GL_FRAMEBUFFER, m_OutputFBO);
                glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                        GL_TEXTURE_2D, 0, 0);
            }
        }
        glproc::BindFramebuffer(GL_FRAMEBUFFER, oldFBOID);
        GLContext::checkError("~FBO");
    }
}

void FBO::activate() const
{
    glproc::BindFramebuffer(GL_FRAMEBUFFER, m_FBO);
    GLContext::checkError("FBO::activate: BindFramebuffer()");
    checkError("activate");
}

PixelFormat FBO::getPF() const
{
    return m_PF;
}

unsigned FBO::getNumTextures() const
{
    return m_pTextures.size();
}

void FBO::copyToDestTexture() const
{
#ifndef AVG_ENABLE_EGL
    if (m_MultisampleSamples != 1) {
        // Copy Multisample FBO to destination fbo
        glproc::BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_FBO);
        glproc::BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_OutputFBO);
        glproc::BlitFramebuffer(0, 0, m_Size.x, m_Size.y, 0, 0, m_Size.x, m_Size.y,
                GL_COLOR_BUFFER_BIT, GL_LINEAR);
        glproc::BindFramebuffer(GL_FRAMEBUFFER, 0);
    }
#endif
    if (m_bMipmap) {
        for (unsigned i=0; i< m_pTextures.size(); ++i) {
            m_pTextures[i]->generateMipmaps();
        }
    }
}

BitmapPtr FBO::getImage(int i) const
{
    GLContext* pContext = GLContext::getCurrent();
    if (pContext->getMemoryMode() == MM_PBO) {
        moveToPBO(i);
        return getImageFromPBO();
    } else {
        BitmapPtr pBmp(new Bitmap(m_Size, m_PF));
        glproc::BindFramebuffer(GL_FRAMEBUFFER, m_OutputFBO);
        glReadPixels(0, 0, m_Size.x, m_Size.y, GLTexture::getGLReadFormat(m_PF),
                GLTexture::getGLType(m_PF), pBmp->getPixels());
        if (pContext->isGLES()) {
            FilterFlipRGB(!pContext->isGLES()).applyInPlace(pBmp);
        }
        GLContext::checkError("FBO::getImage ReadPixels()");
        return pBmp;
    }
}

void FBO::moveToPBO(int i) const
{
    AVG_ASSERT(GLContext::getCurrent()->getMemoryMode() == MM_PBO);
#ifndef AVG_ENABLE_EGL
    // Get data directly from the FBO using glReadBuffer. At least on NVidia/Linux, this
    // is faster than reading stuff from the texture.
    copyToDestTexture();
    glproc::BindFramebuffer(GL_FRAMEBUFFER, m_OutputFBO);

    m_pOutputPBO->activate();
    GLContext::checkError("FBO::moveToPBO BindBuffer()");
    glReadBuffer(GL_COLOR_ATTACHMENT0+i);
    GLContext::checkError("FBO::moveToPBO ReadBuffer()");

    glReadPixels(0, 0, m_Size.x, m_Size.y, GLTexture::getGLFormat(m_PF),
            GLTexture::getGLType(m_PF), 0);
    GLContext::checkError("FBO::moveToPBO ReadPixels()");
#endif
}

BitmapPtr FBO::getImageFromPBO() const
{
#ifdef AVG_ENABLE_EGL
    AVG_ASSERT(false);
    return BitmapPtr();
#else
    AVG_ASSERT(GLContext::getCurrent()->getMemoryMode() == MM_PBO);
    m_pOutputPBO->activate();
    GLContext::checkError("FBO::getImageFromPBO BindBuffer()");

    BitmapPtr pBmp(new Bitmap(m_Size, m_PF));
    void * pPBOPixels = glproc::MapBuffer(GL_PIXEL_PACK_BUFFER_EXT, GL_READ_ONLY);
    GLContext::checkError("FBO::getImageFromPBO MapBuffer()");
    Bitmap PBOBitmap(m_Size, m_PF, (unsigned char *)pPBOPixels,
            m_Size.x*getBytesPerPixel(m_PF), false);
    pBmp->copyPixels(PBOBitmap);
    glproc::UnmapBuffer(GL_PIXEL_PACK_BUFFER_EXT);
    GLContext::checkError("FBO::getImageFromPBO UnmapBuffer()");
    return pBmp;
#endif
}

GLTexturePtr FBO::getTex(int i) const
{
    return m_pTextures[i];
}

const IntPoint& FBO::getSize() const
{
    return m_Size;
}

unsigned FBO::getID() const
{
    return m_FBO;
}

void FBO::init()
{
    GLContext* pContext = GLContext::getCurrent();
    if (m_bUsePackedDepthStencil && !isPackedDepthStencilSupported()) {
        throw Exception(AVG_ERR_UNSUPPORTED, "OpenGL implementation does not support offscreen cropping (GL_EXT_packed_depth_stencil).");
    }
    if (m_MultisampleSamples > 1 && !isMultisampleFBOSupported()) {
        throw Exception(AVG_ERR_UNSUPPORTED, "OpenGL implementation does not support multisample offscreen rendering (GL_EXT_framebuffer_multisample).");
    }
#ifndef AVG_ENABLE_EGL
    if (GLContext::getCurrent()->getMemoryMode() == MM_PBO) {
        m_pOutputPBO = PBOPtr(new PBO(m_Size, m_PF, GL_STREAM_READ));
    }
#endif

    m_FBO = pContext->genFBO();
    GLContext::checkError("FBO::init: GenFramebuffers()");

    glproc::BindFramebuffer(GL_FRAMEBUFFER, m_FBO);
    GLContext::checkError("FBO::init: BindFramebuffer()");

    if (m_MultisampleSamples == 1) {
        for (unsigned i=0; i<m_pTextures.size(); ++i) {
            glproc::FramebufferTexture2D(GL_FRAMEBUFFER,
                    GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D,
                    m_pTextures[i]->getID(), 0);
            GLContext::checkError("FBO: glFramebufferTexture2D()");
        }
        if (m_bUsePackedDepthStencil) {
            glproc::GenRenderbuffers(1, &m_StencilBuffer);
            glproc::BindRenderbuffer(GL_RENDERBUFFER, m_StencilBuffer);
            glproc::RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL_EXT,
                    m_Size.x, m_Size.y);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                    GL_RENDERBUFFER, m_StencilBuffer);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                    GL_RENDERBUFFER, m_StencilBuffer);
            GLContext::checkError("FBO::init: FramebufferRenderbuffer(STENCIL)");
        }
        m_OutputFBO = m_FBO;
    } else {
#ifdef AVG_ENABLE_EGL
        AVG_ASSERT(false);
#else
        glproc::GenRenderbuffers(1, &m_ColorBuffer);
        glproc::BindRenderbuffer(GL_RENDERBUFFER, m_ColorBuffer);
        GLContext::enableErrorLog(false);
        glproc::RenderbufferStorageMultisample(GL_RENDERBUFFER, m_MultisampleSamples,
                GL_RGBA8, m_Size.x, m_Size.y);
        GLContext::enableErrorLog(true);
        GLenum err = glGetError();
        if (err == GL_INVALID_VALUE) {
            glproc::BindFramebuffer(GL_FRAMEBUFFER, 0);
            glproc::DeleteFramebuffers(1, &m_FBO);
            glproc::DeleteRenderbuffers(1, &m_ColorBuffer);
            m_pOutputPBO = PBOPtr();
            throw(Exception(AVG_ERR_UNSUPPORTED,
                    string("Unsupported value for number of multisample samples (")
                    + toString(m_MultisampleSamples) + ")."));
        }
        GLContext::checkError("FBO::init: RenderbufferStorageMultisample");
        glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_RENDERBUFFER, m_ColorBuffer);
        GLContext::checkError("FBO::init: FramebufferRenderbuffer");
        if (m_bUsePackedDepthStencil) {
            glproc::GenRenderbuffers(1, &m_StencilBuffer);
            glproc::BindRenderbuffer(GL_RENDERBUFFER, m_StencilBuffer);
            glproc::RenderbufferStorageMultisample(GL_RENDERBUFFER,
                    m_MultisampleSamples, GL_DEPTH_STENCIL_EXT, m_Size.x, m_Size.y);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                    GL_RENDERBUFFER, m_StencilBuffer);
            glproc::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                    GL_RENDERBUFFER, m_StencilBuffer);
            GLContext::checkError("FBO::init: FramebufferRenderbuffer(STENCIL)");
        }
        checkError("init multisample");
        m_OutputFBO = pContext->genFBO();
        glproc::BindFramebuffer(GL_FRAMEBUFFER, m_OutputFBO);
        glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D, m_pTextures[0]->getID(), 0);

        GLContext::checkError("FBO::init: Multisample init");
#endif
    }

    checkError("init");
    glproc::BindFramebuffer(GL_FRAMEBUFFER, 0);
}

bool FBO::isFBOSupported()
{
    return GLContext::getCurrent()->isGLES() ||
            queryOGLExtension("GL_EXT_framebuffer_object");
}

bool FBO::isMultisampleFBOSupported()
{
#ifdef AVG_ENABLE_EGL
    return false;
#else
    int maxSamples;
    glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
    GLenum err = glGetError();
    if (err != GL_NO_ERROR) {
        return false;
    }
    return queryOGLExtension("GL_EXT_framebuffer_multisample") &&
            queryOGLExtension("GL_EXT_framebuffer_blit") && maxSamples > 1;
#endif
}

bool FBO::isPackedDepthStencilSupported()
{
    return queryOGLExtension("GL_EXT_packed_depth_stencil") ||
            queryOGLExtension("GL_OES_packed_depth_stencil");
}

void FBO::checkError(const string& sContext)
{
    GLenum status = glproc::CheckFramebufferStatus(GL_FRAMEBUFFER);
    string sErr;
    switch (status) {
        case GL_FRAMEBUFFER_COMPLETE:
            return;
        case GL_FRAMEBUFFER_UNSUPPORTED:
            sErr = "GL_FRAMEBUFFER_UNSUPPORTED";
            throw Exception(AVG_ERR_UNSUPPORTED, string("Framebuffer error: ")+sErr);
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            sErr = "GL_INCOMPLETE_ATTACHMENT";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
            break;
#ifndef AVG_ENABLE_EGL
        case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
            sErr = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT";
            break;
        case GL_FRAMEBUFFER_BINDING_EXT:
            sErr = "GL_FRAMEBUFFER_BINDING_EXT";
            break;
#endif
        default:
            sErr = "Unknown error";
            break;
    }
    cerr << "Framebuffer error (" << sContext << "): " << sErr << endl;
    AVG_ASSERT(false);
}

}

<|endoftext|>


<commit_before>#include "emulatorcanvas.h"

#include <cstdint>
#include <iostream>

#include "res/blip.h"

EmulatorCanvas::EmulatorCanvas(QWidget* Parent) :
  QSFMLCanvas(Parent)
{
  worker = new EmulationWorker();
  connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
}

EmulatorCanvas::~EmulatorCanvas()
{
  worker->terminate();
  worker->wait();
}

bool EmulatorCanvas::loadFile(std::string filename)
{
  this->filename = filename;
  return worker->emu.loadGame(filename);
}

bool EmulatorCanvas::reloadFile()
{
  loadFile(filename);
}

void EmulatorCanvas::setFrameRate(unsigned int frameRate)
{
  worker->setFrameRate(frameRate);
}

void EmulatorCanvas::updateInput()
{
  // get keys
  std::array<std::uint8_t, 16> keys;
  for (int i = 0; i < 16; i++)
    keys[i] = sf::Keyboard::isKeyPressed(layout[i]);

  worker->emu.setKeys(keys);
}

void EmulatorCanvas::OnInit()
{
  // graphics
  shape.setSize(sf::Vector2<float>(10, 10));
  shape.setFillColor(sf::Color::Green);

  // sound
  if (!buffer.loadFromMemory(blip.data(), blip.size()))
    std::cerr << "Could not load audio resources, continuing without!" << std::endl;
  else
    sound.setBuffer(buffer);

  worker->start();
}

void EmulatorCanvas::OnRepaint()
{
  worker->paused = !focus;
  if (!focus) return;

  updateInput();

  // draw
  if (worker->emu.drawFlag) {
    worker->emu.drawFlag = false;

    render.clear(sf::Color(0,0,0,255));

    for (int x = 0; x < 64; x++) {
      for (int y = 0; y < 32; y++) {
        if (worker->emu.gfx[x + y*64]) {
          shape.setPosition(x*10, y*10);
          render.draw(shape);
        }
      }
    }
  }

  if (worker->emu.beep)
    sound.play();
}
<commit_msg>Fix return value of reloadFile.<commit_after>#include "emulatorcanvas.h"

#include <cstdint>
#include <iostream>

#include "res/blip.h"

EmulatorCanvas::EmulatorCanvas(QWidget* Parent) :
  QSFMLCanvas(Parent)
{
  worker = new EmulationWorker();
  connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
}

EmulatorCanvas::~EmulatorCanvas()
{
  worker->terminate();
  worker->wait();
}

bool EmulatorCanvas::loadFile(std::string filename)
{
  this->filename = filename;
  return worker->emu.loadGame(filename);
}

bool EmulatorCanvas::reloadFile()
{
  return loadFile(filename);
}

void EmulatorCanvas::setFrameRate(unsigned int frameRate)
{
  worker->setFrameRate(frameRate);
}

void EmulatorCanvas::updateInput()
{
  // get keys
  std::array<std::uint8_t, 16> keys;
  for (int i = 0; i < 16; i++)
    keys[i] = sf::Keyboard::isKeyPressed(layout[i]);

  worker->emu.setKeys(keys);
}

void EmulatorCanvas::OnInit()
{
  // graphics
  shape.setSize(sf::Vector2<float>(10, 10));
  shape.setFillColor(sf::Color::Green);

  // sound
  if (!buffer.loadFromMemory(blip.data(), blip.size()))
    std::cerr << "Could not load audio resources, continuing without!" << std::endl;
  else
    sound.setBuffer(buffer);

  worker->start();
}

void EmulatorCanvas::OnRepaint()
{
  worker->paused = !focus;
  if (!focus) return;

  updateInput();

  // draw
  if (worker->emu.drawFlag) {
    worker->emu.drawFlag = false;

    render.clear(sf::Color(0,0,0,255));

    for (int x = 0; x < 64; x++) {
      for (int y = 0; y < 32; y++) {
        if (worker->emu.gfx[x + y*64]) {
          shape.setPosition(x*10, y*10);
          render.draw(shape);
        }
      }
    }
  }

  if (worker->emu.beep)
    sound.play();
}
<|endoftext|>