<commit_before>/*
 * opencog/atoms/execution/ExecutionOutputLink.cc
 *
 * Copyright (C) 2009, 2013, 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <dlfcn.h>
#include <stdlib.h>

#include <opencog/atoms/base/atom_types.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/core/DefineLink.h>
#include <opencog/cython/PythonEval.h>
#include <opencog/guile/SchemeEval.h>

#include "ExecutionOutputLink.h"
#include "Force.h"

using namespace opencog;

class LibraryManager
{
private:
    static std::unordered_map<std::string, void*> _librarys;
    static std::unordered_map<std::string, void*> _functions;
public:
    static void* getFunc(std::string libName,std::string funcName);
};

ExecutionOutputLink::ExecutionOutputLink(const HandleSeq& oset, Type t)
	: FunctionLink(oset, t)
{
	if (EXECUTION_OUTPUT_LINK != t)
		throw SyntaxException(TRACE_INFO,
			"Expection an ExecutionOutputLink!");

	if (2 != oset.size())
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have schema and args! Got arity=%d",
			oset.size());

	if (DEFINED_SCHEMA_NODE != oset[0]->getType() and
	    LAMBDA_LINK != oset[0]->getType() and
	    GROUNDED_SCHEMA_NODE != oset[0]->getType())
	{
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have schema! Got %s",
			oset[0]->toString().c_str());
	}
}

ExecutionOutputLink::ExecutionOutputLink(const Handle& schema,
                                         const Handle& args)
	: FunctionLink(EXECUTION_OUTPUT_LINK, schema, args)
{
	Type stype = schema->getType();
	if (GROUNDED_SCHEMA_NODE != stype and
	    LAMBDA_LINK != stype and
	    DEFINED_SCHEMA_NODE != stype)
	{
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink expecting schema, got %s",
			schema->toString().c_str());
	}
}

ExecutionOutputLink::ExecutionOutputLink(const Link& l)
	: FunctionLink(l)
{
	Type tscope = l.getType();
	if (EXECUTION_OUTPUT_LINK != tscope)
		throw SyntaxException(TRACE_INFO,
			"Expection an ExecutionOutputLink!");
}

/// execute -- execute the function defined in an ExecutionOutputLink
///
/// Each ExecutionOutputLink should have the form:
///
///     ExecutionOutputLink
///         GroundedSchemaNode "lang: func_name"
///         ListLink
///             SomeAtom
///             OtherAtom
///
/// The "lang:" should be either "scm:" for scheme, or "py:" for python.
/// This method will then invoke "func_name" on the provided ListLink
/// of arguments to the function.
///
Handle ExecutionOutputLink::execute(AtomSpace* as) const
{
	return do_execute(as, _outgoing[0], _outgoing[1]);
}

/// do_execute -- execute the SchemaNode of the ExecutionOutputLink
///
/// Expects "gsn" to be a GroundedSchemaNode or a DefinedSchemaNode
/// Expects "args" to be a ListLink
/// Executes the GroundedSchemaNode, supplying the args as argument
///
Handle ExecutionOutputLink::do_execute(AtomSpace* as,
                         const Handle& gsn, const Handle& cargs)
{
	LAZY_LOG_FINE << "Execute gsn: " << gsn->toShortString()
	              << "with arguments: " << cargs->toShortString();

	// Force execution of the arguments. We have to do this, because
	// the user-defined functions are black-boxes, and cannot be trusted
	// to do lazy execution correctly. Right now, forcing is the policy.
	// We could add "scm-lazy:" and "py-lazy:" URI's for user-defined
	// functions smart enough to do lazy evaluation.
	Handle args = force_execute(as, cargs);

	// Get the schema name.
	const std::string& schema = gsn->getName();

	// Extract the language, library and function
	std::string lang, lib, fun;
	lang_lib_fun(schema, lang, lib, fun);

	Handle result;

	// At this point, we only run scheme, python schemas and functions from
	// libraries loaded at runtime.
	if (lang == "scm")
	{
#ifdef HAVE_GUILE
		SchemeEval* applier = SchemeEval::get_evaluator(as);
		result = applier->apply(fun, args);

		// Exceptions were already caught, before leaving guile mode,
		// so we can't rethrow.  Just throw a new exception.
		if (applier->eval_error())
			throw RuntimeException(TRACE_INFO,
			    "Failed evaluation; see logfile for stack trace.");
#else
		throw RuntimeException(TRACE_INFO,
		    "Cannot evaluate scheme GroundedSchemaNode!");
#endif /* HAVE_GUILE */
	}
	else if (lang == "py")
	{
#ifdef HAVE_CYTHON
		// Get a reference to the python evaluator.
		// Be sure to specify the atomspace in which the
		// evaluation is to be performed.
		PythonEval &applier = PythonEval::instance();
		result = applier.apply(as, fun, args);
#else
		throw RuntimeException(TRACE_INFO,
		    "Cannot evaluate python GroundedSchemaNode!");
#endif /* HAVE_CYTHON */
	}
	// Used by the Haskel bindings
	else if (lang == "lib")
	{
#define BROKEN_CODE
#ifdef BROKEN_CODE
		void* sym = LibraryManager::getFunc(lib,fun);

		// Convert the void* pointer to the correct function type.
		Handle* (*func)(AtomSpace*, Handle*);
		func = reinterpret_cast<Handle* (*)(AtomSpace *, Handle*)>(sym);

		// Execute the function
		result = *func(as, &args);
#endif
	}
	else {
		// Unkown proceedure type
		throw RuntimeException(TRACE_INFO,
		                       "Cannot evaluate unknown Schema %s",
		                       gsn->toString().c_str());
	}

	// Check for a not-uncommon user-error.  If the user-defined
	// code returns nothing, then a null-pointer-dereference is
	// likely, a bit later down the line, leading to a crash.
	// So head this off at the pass.
	if (nullptr == result) {
		// If silent is true, return a simpler and non-logged
		// exception, which may, in some contexts, be considerably
		// faster than the one below.
		if (silent)
			throw NotEvaluatableException;

		throw RuntimeException(TRACE_INFO,
		        "Invalid return value from schema %s\nArgs: %s",
		        gsn->toString().c_str(),
		        cargs->toString().c_str());
	}

	LAZY_LOG_FINE << "Result: " << oc_to_string(result);
	return result;
}

void ExecutionOutputLink::lang_lib_fun(const std::string& schema,
                                       std::string& lang,
                                       std::string& lib,
                                       std::string& fun)
{
	std::string::size_type pos = schema.find(":");
	if (pos == std::string::npos)
		return;

	lang = schema.substr(0, pos);

	// Move past the colon and strip leading white-space
	do { pos++; } while (' ' == schema[pos]);

	if (lang == "lib") {
		// Get the name of the Library and Function. They should be
		// sperated by "\\".
		std::size_t seppos = schema.find("\\");
		if (seppos == std::string::npos)
		{
			throw RuntimeException(TRACE_INFO,
				"Library name and function name must be separated by '\\'");
		}
		lib = schema.substr(pos, seppos - pos);
		fun = schema.substr(seppos + 1);
	} else
		fun = schema.substr(pos);
}

DEFINE_LINK_FACTORY(ExecutionOutputLink, EXECUTION_OUTPUT_LINK)

std::unordered_map<std::string, void*> LibraryManager::_librarys;
std::unordered_map<std::string, void*> LibraryManager::_functions;

void* LibraryManager::getFunc(std::string libName,std::string funcName)
{
    void* libHandle;
    if (_librarys.count(libName) == 0) {
        // Try and load the library and function.
        libHandle = dlopen(libName.c_str(), RTLD_LAZY);
        if (nullptr == libHandle)
            throw RuntimeException(TRACE_INFO,
                "Cannot open library: %s - %s", libName.c_str(), dlerror());
        _librarys[libName] = libHandle;
    }
    else {
        libHandle = _librarys[libName];
    }

    std::string funcID = libName + "\\" + funcName;

    void* sym;
    if (_functions.count(funcID) == 0){
        sym = dlsym(libHandle, funcName.c_str());
        if (nullptr == sym)
            throw RuntimeException(TRACE_INFO,
                "Cannot find symbol %s in library: %s - %s",
                funcName.c_str(), libName.c_str(), dlerror());
        _functions[funcID] = sym;
    }
    else {
        sym = _functions[funcID];
    }

    return sym;
}
<commit_msg>Add on for now silent flag<commit_after>/*
 * opencog/atoms/execution/ExecutionOutputLink.cc
 *
 * Copyright (C) 2009, 2013, 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <dlfcn.h>
#include <stdlib.h>

#include <opencog/atoms/base/atom_types.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/core/DefineLink.h>
#include <opencog/cython/PythonEval.h>
#include <opencog/guile/SchemeEval.h>

#include "ExecutionOutputLink.h"
#include "Force.h"

using namespace opencog;

class LibraryManager
{
private:
    static std::unordered_map<std::string, void*> _librarys;
    static std::unordered_map<std::string, void*> _functions;
public:
    static void* getFunc(std::string libName,std::string funcName);
};

ExecutionOutputLink::ExecutionOutputLink(const HandleSeq& oset, Type t)
	: FunctionLink(oset, t)
{
	if (EXECUTION_OUTPUT_LINK != t)
		throw SyntaxException(TRACE_INFO,
			"Expection an ExecutionOutputLink!");

	if (2 != oset.size())
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have schema and args! Got arity=%d",
			oset.size());

	if (DEFINED_SCHEMA_NODE != oset[0]->getType() and
	    LAMBDA_LINK != oset[0]->getType() and
	    GROUNDED_SCHEMA_NODE != oset[0]->getType())
	{
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have schema! Got %s",
			oset[0]->toString().c_str());
	}
}

ExecutionOutputLink::ExecutionOutputLink(const Handle& schema,
                                         const Handle& args)
	: FunctionLink(EXECUTION_OUTPUT_LINK, schema, args)
{
	Type stype = schema->getType();
	if (GROUNDED_SCHEMA_NODE != stype and
	    LAMBDA_LINK != stype and
	    DEFINED_SCHEMA_NODE != stype)
	{
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink expecting schema, got %s",
			schema->toString().c_str());
	}
}

ExecutionOutputLink::ExecutionOutputLink(const Link& l)
	: FunctionLink(l)
{
	Type tscope = l.getType();
	if (EXECUTION_OUTPUT_LINK != tscope)
		throw SyntaxException(TRACE_INFO,
			"Expection an ExecutionOutputLink!");
}

/// execute -- execute the function defined in an ExecutionOutputLink
///
/// Each ExecutionOutputLink should have the form:
///
///     ExecutionOutputLink
///         GroundedSchemaNode "lang: func_name"
///         ListLink
///             SomeAtom
///             OtherAtom
///
/// The "lang:" should be either "scm:" for scheme, or "py:" for python.
/// This method will then invoke "func_name" on the provided ListLink
/// of arguments to the function.
///
Handle ExecutionOutputLink::execute(AtomSpace* as) const
{
	return do_execute(as, _outgoing[0], _outgoing[1]);
}

/// do_execute -- execute the SchemaNode of the ExecutionOutputLink
///
/// Expects "gsn" to be a GroundedSchemaNode or a DefinedSchemaNode
/// Expects "args" to be a ListLink
/// Executes the GroundedSchemaNode, supplying the args as argument
///
Handle ExecutionOutputLink::do_execute(AtomSpace* as,
                         const Handle& gsn, const Handle& cargs)
{
	LAZY_LOG_FINE << "Execute gsn: " << gsn->toShortString()
	              << "with arguments: " << cargs->toShortString();

	// Force execution of the arguments. We have to do this, because
	// the user-defined functions are black-boxes, and cannot be trusted
	// to do lazy execution correctly. Right now, forcing is the policy.
	// We could add "scm-lazy:" and "py-lazy:" URI's for user-defined
	// functions smart enough to do lazy evaluation.
	Handle args = force_execute(as, cargs);

	// Get the schema name.
	const std::string& schema = gsn->getName();

	// Extract the language, library and function
	std::string lang, lib, fun;
	lang_lib_fun(schema, lang, lib, fun);

	Handle result;

	// At this point, we only run scheme, python schemas and functions from
	// libraries loaded at runtime.
	if (lang == "scm")
	{
#ifdef HAVE_GUILE
		SchemeEval* applier = SchemeEval::get_evaluator(as);
		result = applier->apply(fun, args);

		// Exceptions were already caught, before leaving guile mode,
		// so we can't rethrow.  Just throw a new exception.
		if (applier->eval_error())
			throw RuntimeException(TRACE_INFO,
			    "Failed evaluation; see logfile for stack trace.");
#else
		throw RuntimeException(TRACE_INFO,
		    "Cannot evaluate scheme GroundedSchemaNode!");
#endif /* HAVE_GUILE */
	}
	else if (lang == "py")
	{
#ifdef HAVE_CYTHON
		// Get a reference to the python evaluator.
		// Be sure to specify the atomspace in which the
		// evaluation is to be performed.
		PythonEval &applier = PythonEval::instance();
		result = applier.apply(as, fun, args);
#else
		throw RuntimeException(TRACE_INFO,
		    "Cannot evaluate python GroundedSchemaNode!");
#endif /* HAVE_CYTHON */
	}
	// Used by the Haskel bindings
	else if (lang == "lib")
	{
#define BROKEN_CODE
#ifdef BROKEN_CODE
		void* sym = LibraryManager::getFunc(lib,fun);

		// Convert the void* pointer to the correct function type.
		Handle* (*func)(AtomSpace*, Handle*);
		func = reinterpret_cast<Handle* (*)(AtomSpace *, Handle*)>(sym);

		// Execute the function
		result = *func(as, &args);
#endif
	}
	else {
		// Unkown proceedure type
		throw RuntimeException(TRACE_INFO,
		                       "Cannot evaluate unknown Schema %s",
		                       gsn->toString().c_str());
	}

	// Check for a not-uncommon user-error.  If the user-defined
	// code returns nothing, then a null-pointer-dereference is
	// likely, a bit later down the line, leading to a crash.
	// So head this off at the pass.
	if (nullptr == result) {
		bool silent = true;
		// If silent is true, return a simpler and non-logged
		// exception, which may, in some contexts, be considerably
		// faster than the one below.
		if (silent)
			throw NotEvaluatableException();

		throw RuntimeException(TRACE_INFO,
		        "Invalid return value from schema %s\nArgs: %s",
		        gsn->toString().c_str(),
		        cargs->toString().c_str());
	}

	LAZY_LOG_FINE << "Result: " << oc_to_string(result);
	return result;
}

void ExecutionOutputLink::lang_lib_fun(const std::string& schema,
                                       std::string& lang,
                                       std::string& lib,
                                       std::string& fun)
{
	std::string::size_type pos = schema.find(":");
	if (pos == std::string::npos)
		return;

	lang = schema.substr(0, pos);

	// Move past the colon and strip leading white-space
	do { pos++; } while (' ' == schema[pos]);

	if (lang == "lib") {
		// Get the name of the Library and Function. They should be
		// sperated by "\\".
		std::size_t seppos = schema.find("\\");
		if (seppos == std::string::npos)
		{
			throw RuntimeException(TRACE_INFO,
				"Library name and function name must be separated by '\\'");
		}
		lib = schema.substr(pos, seppos - pos);
		fun = schema.substr(seppos + 1);
	} else
		fun = schema.substr(pos);
}

DEFINE_LINK_FACTORY(ExecutionOutputLink, EXECUTION_OUTPUT_LINK)

std::unordered_map<std::string, void*> LibraryManager::_librarys;
std::unordered_map<std::string, void*> LibraryManager::_functions;

void* LibraryManager::getFunc(std::string libName,std::string funcName)
{
    void* libHandle;
    if (_librarys.count(libName) == 0) {
        // Try and load the library and function.
        libHandle = dlopen(libName.c_str(), RTLD_LAZY);
        if (nullptr == libHandle)
            throw RuntimeException(TRACE_INFO,
                "Cannot open library: %s - %s", libName.c_str(), dlerror());
        _librarys[libName] = libHandle;
    }
    else {
        libHandle = _librarys[libName];
    }

    std::string funcID = libName + "\\" + funcName;

    void* sym;
    if (_functions.count(funcID) == 0){
        sym = dlsym(libHandle, funcName.c_str());
        if (nullptr == sym)
            throw RuntimeException(TRACE_INFO,
                "Cannot find symbol %s in library: %s - %s",
                funcName.c_str(), libName.c_str(), dlerror());
        _functions[funcID] = sym;
    }
    else {
        sym = _functions[funcID];
    }

    return sym;
}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "mitkGlobalInteraction.h"
#include "mitkInteractionConst.h"
#include "mitkEvent.h"
#include "mitkAction.h"
#include "mitkStateEvent.h"
#include <mitkStatusBar.h>
#include <mitkPositionEvent.h>
#include <vtkWorldPointPicker.h>
#include <mitkOpenGLRenderer.h>

mitk::GlobalInteraction::Pointer mitk::GlobalInteraction::s_GlobalInteraction(NULL);

mitk::GlobalInteraction::GlobalInteraction(const char * type)
: StateMachine(type)
{
  //build up the FocusManager
  m_FocusManager = new mitk::FocusManager();
  m_InteractionDebugger = InteractionDebugger::New();
  InteractionDebugger::Deactivate();
}

mitk::GlobalInteraction::~GlobalInteraction()
{
  //s_GlobalInteraction doesn't have to be set = NULL;
}

inline mitk::StateEvent* GenerateEmptyStateEvent(int eventId)
{
  mitk::Event *noEvent = new mitk::Event(NULL,
    mitk::Type_User,
    mitk::BS_NoButton,
    mitk::BS_NoButton,
    mitk::Key_none);
  mitk::StateEvent *stateEvent = new mitk::StateEvent(eventId, noEvent);
  return stateEvent;
}

void mitk::GlobalInteraction::AddListener(mitk::StateMachine* listener)
{
  if(listener == NULL) return;
  if(dynamic_cast<Interactor*>(listener)!=NULL)
  {
    itkWarningMacro(<<"Trying to add an Interactor ("
      << listener->GetNameOfClass() << ") as a listener. "
      << "This will probably cause problems");
  }
  if ( std::find(m_ListenerList.begin(), m_ListenerList.end(),listener) == m_ListenerList.end() )
  {
    m_ListenerList.push_back(listener);
  }
}

bool mitk::GlobalInteraction::RemoveListener(mitk::StateMachine* listener)
{
  // Try find
  StateMachineListIter position = std::find(m_ListenerList.begin(), m_ListenerList.end(),listener);
  if (position == m_ListenerList.end())
    return false;
  position = m_ListenerList.erase(position);
  return true;
}

void mitk::GlobalInteraction::AddInteractor(mitk::Interactor* interactor)
{
  if(interactor == NULL) return;
  if ( std::find(m_InteractorList.begin(), m_InteractorList.end(),interactor) == m_InteractorList.end() )
  {
    m_InteractorList.push_back(interactor);

    //if Interactor already selected, then add to selected list
    if (interactor->GetMode()==Interactor::SMSELECTED)
      this->AddToSelectedInteractors(interactor);
  }
}

bool mitk::GlobalInteraction::InteractorRegistered (mitk::Interactor* interactor)
{
  if ( std::find(m_InteractorList.begin(), m_InteractorList.end(), interactor) == m_InteractorList.end() )
    return false;
  else
    return true;
}

bool mitk::GlobalInteraction::ListenerRegistered (mitk::Interactor* interactor)
{
  if ( std::find(m_ListenerList.begin(), m_ListenerList.end(), interactor) == m_ListenerList.end() )
    return false;
  else
    return true;
}

bool mitk::GlobalInteraction::RemoveInteractor(mitk::Interactor* interactor)
{
  InteractorListIter position = std::find(m_InteractorList.begin(), m_InteractorList.end(),interactor);
  if (position == m_InteractorList.end())
    return false;
  position = m_InteractorList.erase(position);

  //check if the interactor is also held in SelectedList
  this->RemoveFromSelectedInteractors(interactor);

  //check if in JurisdictionMap
  for (InteractorMapIter it = m_JurisdictionMap.begin(); it != m_JurisdictionMap.end(); it++)
  {
    if ((*it).second == interactor)
    {
      m_JurisdictionMap.erase(it);
      if (m_CurrentInteractorIter == it)
        m_CurrentInteractorIter == m_JurisdictionMap.end();
      break;
    }
  }

  return true;
}

void mitk::GlobalInteraction::InformListeners(mitk::StateEvent const* stateEvent)
{
  for (StateMachineListIter it = m_ListenerList.begin(); it != m_ListenerList.end(); it++)
  {
    if((*it).IsNotNull())
      (*it)->HandleEvent(stateEvent);
  }
}

bool mitk::GlobalInteraction::AskSelected(mitk::StateEvent const* stateEvent)
{
  if (m_SelectedList.empty())
    return false;

  bool ok = false, oneOk = false;

  //copy of m_SelectedList to be stable if an iterator gets removed during the following steps
  InteractorList copyOfSelectedList = m_SelectedList;
  InteractorListIter it = copyOfSelectedList.begin();

  for (; it != copyOfSelectedList.end(); it++)
  {
    oneOk = (*it)->HandleEvent(stateEvent);

    //if one HandleEvent did succeed, then set returnvalue on true;
    if (oneOk)
      ok = true;
  }
  return ok;
}

void mitk::GlobalInteraction::FillJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold)
{
  m_JurisdictionMap.clear();

  for (InteractorListIter it = m_InteractorList.begin(); it != m_InteractorList.end(); it++)
  {
    if ((*it).IsNotNull())
    {
      //first ask for CalculateJurisdiction(..) and write it into the map if > 0
      float value = (*it)->CalculateJurisdiction(stateEvent);
      if (value > threshold)
      {
        m_JurisdictionMap.insert(InteractorMap::value_type(value, (*it)));
      }
    }
  }
  //set the iterator to the first element to start stepping through interactors
  if (! m_JurisdictionMap.empty())
    m_CurrentInteractorIter = m_JurisdictionMap.begin();
  else
    m_CurrentInteractorIter = m_JurisdictionMap.end();
}

/*
* Go through the list of interactors, that could possibly handle an event and ask if it has handled the event.
* If an interactor has handled an event, it should add itself to the list of selectedInteractors
* Ask as long as no interactor answers, that it could be handled
*/
bool mitk::GlobalInteraction::AskCurrentInteractor(mitk::StateEvent const* stateEvent)
{
  //no need to check if we don't have any interactors. nearly equal to m_CurrentInteractorIter == m_JurisdictionMap.end
  if (m_JurisdictionMap.empty())
    return false;

  bool handled = false;
  while ( m_CurrentInteractorIter != m_JurisdictionMap.end()&& !handled)
  {
    handled = (*m_CurrentInteractorIter).second->HandleEvent(stateEvent);

    if (!handled)
      m_CurrentInteractorIter++;
  }

  //loop for later usage
  if (m_CurrentInteractorIter == m_JurisdictionMap.end())
    m_CurrentInteractorIter = m_JurisdictionMap.begin();
  return handled;
}

bool mitk::GlobalInteraction::AddFocusElement(mitk::FocusManager::FocusElement* element)
{
  return m_FocusManager->AddElement(element);
}

bool mitk::GlobalInteraction::RemoveFocusElement(mitk::FocusManager::FocusElement* element)
{
  return m_FocusManager->RemoveElement(element);
}

mitk::FocusManager::FocusElement* mitk::GlobalInteraction::GetFocus()
{
  return m_FocusManager->GetFocused();
}

bool mitk::GlobalInteraction::SetFocus(mitk::FocusManager::FocusElement* element)
{
  return m_FocusManager->SetFocused(element);
}

mitk::FocusManager* mitk::GlobalInteraction::GetFocusManager()
{
  return m_FocusManager;
}

bool mitk::GlobalInteraction::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent)
{
  bool ok = false;

  ok = false;
  switch (action->GetActionId())
  {
  case AcDONOTHING:
    ok = true;
    break;
  case AcINFORMLISTENERS:
    InformListeners(stateEvent);
    ok = true;
    break;
  case AcASKINTERACTORS:
    if (! AskSelected(stateEvent))//no interactor selected anymore
    {
      //fill the jurisdictionMap to ask them bit by bit.
      //currentInteractor is set here to the beginning
      FillJurisdictionMap(stateEvent, 0);

      //ask the Interactors to handle that event
      AskCurrentInteractor(stateEvent);
    }
    ok = true;
    break;
  default:
    ok = true;
  }
  return ok;
}

#include <mitkStateMachineFactory.h>
#include <mitkEventMapper.h>
bool mitk::GlobalInteraction::StandardInteractionSetup(const char * XMLbehaviorFile, const char * globalInteractionName)
{
  bool result;
  // load interaction patterns from XML-file
  if(XMLbehaviorFile==NULL)
    result=mitk::StateMachineFactory::LoadStandardBehavior();
  else
    result=mitk::StateMachineFactory::LoadBehavior(XMLbehaviorFile);
  if(result==false)
  {
    s_GlobalInteraction = mitk::GlobalInteraction::New(NULL);
    return false;
  }
  // load event-mappings from XML-file
  if(XMLbehaviorFile==NULL)
    result=mitk::EventMapper::LoadStandardBehavior();
  else
    result=mitk::EventMapper::LoadBehavior(XMLbehaviorFile);
  if(result==false)
  {
    s_GlobalInteraction = mitk::GlobalInteraction::New(NULL);
    return false;
  }
  // setup interaction mechanism by creating GlobalInteraction
  if(globalInteractionName == NULL)
    s_GlobalInteraction = mitk::GlobalInteraction::New("global");
  else
    s_GlobalInteraction = mitk::GlobalInteraction::New(globalInteractionName);
  return true;
}

mitk::GlobalInteraction* mitk::GlobalInteraction::GetInstance()
{
  if(s_GlobalInteraction.IsNull())
  {
    mitk::GlobalInteraction::StandardInteractionSetup();
  }
  return s_GlobalInteraction.GetPointer();
}

bool mitk::GlobalInteraction::AddToSelectedInteractors(mitk::Interactor* interactor)
{
  InteractorListIter position = std::find(m_SelectedList.begin(), m_SelectedList.end(),interactor);
  if (position != m_SelectedList.end())
  {
    //already added so don't add once more!
    return true;
  }
  else
    m_SelectedList.push_back(interactor);

  return true;
}

bool mitk::GlobalInteraction::RemoveFromSelectedInteractors(mitk::Interactor* interactor)
{
  if (interactor == NULL)
    return false;

  InteractorListIter position = std::find(m_SelectedList.begin(), m_SelectedList.end(),interactor);
  if (position != m_SelectedList.end())
  {
    position = m_SelectedList.erase(position);
    return true;
  }
  else
    return false;
}

<commit_msg>BUG: Removed bug in RemoveInteractor() found by Jacob Foshee<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "mitkGlobalInteraction.h"
#include "mitkInteractionConst.h"
#include "mitkEvent.h"
#include "mitkAction.h"
#include "mitkStateEvent.h"
#include <mitkStatusBar.h>
#include <mitkPositionEvent.h>
#include <vtkWorldPointPicker.h>
#include <mitkOpenGLRenderer.h>

mitk::GlobalInteraction::Pointer mitk::GlobalInteraction::s_GlobalInteraction(NULL);

mitk::GlobalInteraction::GlobalInteraction(const char * type)
: StateMachine(type)
{
  //build up the FocusManager
  m_FocusManager = new mitk::FocusManager();
  m_InteractionDebugger = InteractionDebugger::New();
  InteractionDebugger::Deactivate();
}

mitk::GlobalInteraction::~GlobalInteraction()
{
  //s_GlobalInteraction doesn't have to be set = NULL;
}

inline mitk::StateEvent* GenerateEmptyStateEvent(int eventId)
{
  mitk::Event *noEvent = new mitk::Event(NULL,
    mitk::Type_User,
    mitk::BS_NoButton,
    mitk::BS_NoButton,
    mitk::Key_none);
  mitk::StateEvent *stateEvent = new mitk::StateEvent(eventId, noEvent);
  return stateEvent;
}

void mitk::GlobalInteraction::AddListener(mitk::StateMachine* listener)
{
  if(listener == NULL) return;
  if(dynamic_cast<Interactor*>(listener)!=NULL)
  {
    itkWarningMacro(<<"Trying to add an Interactor ("
      << listener->GetNameOfClass() << ") as a listener. "
      << "This will probably cause problems");
  }
  if ( std::find(m_ListenerList.begin(), m_ListenerList.end(),listener) == m_ListenerList.end() )
  {
    m_ListenerList.push_back(listener);
  }
}

bool mitk::GlobalInteraction::RemoveListener(mitk::StateMachine* listener)
{
  // Try find
  StateMachineListIter position = std::find(m_ListenerList.begin(), m_ListenerList.end(),listener);
  if (position == m_ListenerList.end())
    return false;
  position = m_ListenerList.erase(position);
  return true;
}

void mitk::GlobalInteraction::AddInteractor(mitk::Interactor* interactor)
{
  if(interactor == NULL) return;
  if ( std::find(m_InteractorList.begin(), m_InteractorList.end(),interactor) == m_InteractorList.end() )
  {
    m_InteractorList.push_back(interactor);

    //if Interactor already selected, then add to selected list
    if (interactor->GetMode()==Interactor::SMSELECTED)
      this->AddToSelectedInteractors(interactor);
  }
}

bool mitk::GlobalInteraction::InteractorRegistered (mitk::Interactor* interactor)
{
  if ( std::find(m_InteractorList.begin(), m_InteractorList.end(), interactor) == m_InteractorList.end() )
    return false;
  else
    return true;
}

bool mitk::GlobalInteraction::ListenerRegistered (mitk::Interactor* interactor)
{
  if ( std::find(m_ListenerList.begin(), m_ListenerList.end(), interactor) == m_ListenerList.end() )
    return false;
  else
    return true;
}

bool mitk::GlobalInteraction::RemoveInteractor(mitk::Interactor* interactor)
{
  InteractorListIter position = std::find(m_InteractorList.begin(), m_InteractorList.end(),interactor);
  if (position == m_InteractorList.end())
    return false;
  position = m_InteractorList.erase(position);

  //check if the interactor is also held in SelectedList
  this->RemoveFromSelectedInteractors(interactor);

  //check if in JurisdictionMap
  for (InteractorMapIter it = m_JurisdictionMap.begin(); it != m_JurisdictionMap.end(); it++)
  {
    if ((*it).second == interactor)
    {
      if (m_CurrentInteractorIter == it)
        m_CurrentInteractorIter = m_JurisdictionMap.end();
      m_JurisdictionMap.erase(it);
      break;
    }
  }

  return true;
}

void mitk::GlobalInteraction::InformListeners(mitk::StateEvent const* stateEvent)
{
  for (StateMachineListIter it = m_ListenerList.begin(); it != m_ListenerList.end(); it++)
  {
    if((*it).IsNotNull())
      (*it)->HandleEvent(stateEvent);
  }
}

bool mitk::GlobalInteraction::AskSelected(mitk::StateEvent const* stateEvent)
{
  if (m_SelectedList.empty())
    return false;

  bool ok = false, oneOk = false;

  //copy of m_SelectedList to be stable if an iterator gets removed during the following steps
  InteractorList copyOfSelectedList = m_SelectedList;
  InteractorListIter it = copyOfSelectedList.begin();

  for (; it != copyOfSelectedList.end(); it++)
  {
    oneOk = (*it)->HandleEvent(stateEvent);

    //if one HandleEvent did succeed, then set returnvalue on true;
    if (oneOk)
      ok = true;
  }
  return ok;
}

void mitk::GlobalInteraction::FillJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold)
{
  m_JurisdictionMap.clear();

  for (InteractorListIter it = m_InteractorList.begin(); it != m_InteractorList.end(); it++)
  {
    if ((*it).IsNotNull())
    {
      //first ask for CalculateJurisdiction(..) and write it into the map if > 0
      float value = (*it)->CalculateJurisdiction(stateEvent);
      if (value > threshold)
      {
        m_JurisdictionMap.insert(InteractorMap::value_type(value, (*it)));
      }
    }
  }
  //set the iterator to the first element to start stepping through interactors
  if (! m_JurisdictionMap.empty())
    m_CurrentInteractorIter = m_JurisdictionMap.begin();
  else
    m_CurrentInteractorIter = m_JurisdictionMap.end();
}

/*
* Go through the list of interactors, that could possibly handle an event and ask if it has handled the event.
* If an interactor has handled an event, it should add itself to the list of selectedInteractors
* Ask as long as no interactor answers, that it could be handled
*/
bool mitk::GlobalInteraction::AskCurrentInteractor(mitk::StateEvent const* stateEvent)
{
  //no need to check if we don't have any interactors. nearly equal to m_CurrentInteractorIter == m_JurisdictionMap.end
  if (m_JurisdictionMap.empty())
    return false;

  bool handled = false;
  while ( m_CurrentInteractorIter != m_JurisdictionMap.end()&& !handled)
  {
    handled = (*m_CurrentInteractorIter).second->HandleEvent(stateEvent);

    if (!handled)
      m_CurrentInteractorIter++;
  }

  //loop for later usage
  if (m_CurrentInteractorIter == m_JurisdictionMap.end())
    m_CurrentInteractorIter = m_JurisdictionMap.begin();
  return handled;
}

bool mitk::GlobalInteraction::AddFocusElement(mitk::FocusManager::FocusElement* element)
{
  return m_FocusManager->AddElement(element);
}

bool mitk::GlobalInteraction::RemoveFocusElement(mitk::FocusManager::FocusElement* element)
{
  return m_FocusManager->RemoveElement(element);
}

mitk::FocusManager::FocusElement* mitk::GlobalInteraction::GetFocus()
{
  return m_FocusManager->GetFocused();
}

bool mitk::GlobalInteraction::SetFocus(mitk::FocusManager::FocusElement* element)
{
  return m_FocusManager->SetFocused(element);
}

mitk::FocusManager* mitk::GlobalInteraction::GetFocusManager()
{
  return m_FocusManager;
}

bool mitk::GlobalInteraction::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent)
{
  bool ok = false;

  ok = false;
  switch (action->GetActionId())
  {
  case AcDONOTHING:
    ok = true;
    break;
  case AcINFORMLISTENERS:
    InformListeners(stateEvent);
    ok = true;
    break;
  case AcASKINTERACTORS:
    if (! AskSelected(stateEvent))//no interactor selected anymore
    {
      //fill the jurisdictionMap to ask them bit by bit.
      //currentInteractor is set here to the beginning
      FillJurisdictionMap(stateEvent, 0);

      //ask the Interactors to handle that event
      AskCurrentInteractor(stateEvent);
    }
    ok = true;
    break;
  default:
    ok = true;
  }
  return ok;
}

#include <mitkStateMachineFactory.h>
#include <mitkEventMapper.h>
bool mitk::GlobalInteraction::StandardInteractionSetup(const char * XMLbehaviorFile, const char * globalInteractionName)
{
  bool result;
  // load interaction patterns from XML-file
  if(XMLbehaviorFile==NULL)
    result=mitk::StateMachineFactory::LoadStandardBehavior();
  else
    result=mitk::StateMachineFactory::LoadBehavior(XMLbehaviorFile);
  if(result==false)
  {
    s_GlobalInteraction = mitk::GlobalInteraction::New(NULL);
    return false;
  }
  // load event-mappings from XML-file
  if(XMLbehaviorFile==NULL)
    result=mitk::EventMapper::LoadStandardBehavior();
  else
    result=mitk::EventMapper::LoadBehavior(XMLbehaviorFile);
  if(result==false)
  {
    s_GlobalInteraction = mitk::GlobalInteraction::New(NULL);
    return false;
  }
  // setup interaction mechanism by creating GlobalInteraction
  if(globalInteractionName == NULL)
    s_GlobalInteraction = mitk::GlobalInteraction::New("global");
  else
    s_GlobalInteraction = mitk::GlobalInteraction::New(globalInteractionName);
  return true;
}

mitk::GlobalInteraction* mitk::GlobalInteraction::GetInstance()
{
  if(s_GlobalInteraction.IsNull())
  {
    mitk::GlobalInteraction::StandardInteractionSetup();
  }
  return s_GlobalInteraction.GetPointer();
}

bool mitk::GlobalInteraction::AddToSelectedInteractors(mitk::Interactor* interactor)
{
  InteractorListIter position = std::find(m_SelectedList.begin(), m_SelectedList.end(),interactor);
  if (position != m_SelectedList.end())
  {
    //already added so don't add once more!
    return true;
  }
  else
    m_SelectedList.push_back(interactor);

  return true;
}

bool mitk::GlobalInteraction::RemoveFromSelectedInteractors(mitk::Interactor* interactor)
{
  if (interactor == NULL)
    return false;

  InteractorListIter position = std::find(m_SelectedList.begin(), m_SelectedList.end(),interactor);
  if (position != m_SelectedList.end())
  {
    position = m_SelectedList.erase(position);
    return true;
  }
  else
    return false;
}

<|endoftext|>


<commit_before>//  Copyright 2016 Peter Georg
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#ifndef pMR_ALLREDUCE_RECURSIVE_DOUBLING_ALLREDUCE_H
#define pMR_ALLREDUCE_RECURSIVE_DOUBLING_ALLREDUCE_H

#include <cstring>
#include "../../communicator.hpp"
#include "../../connection.hpp"
#include "../../misc/allocator.hpp"
#include "../../operations.hpp"
#include "../../recvmemorywindow.hpp"
#include "../../sendmemorywindow.hpp"

#include "../../misc/print.hpp"

namespace pMR
{
    namespace RecursiveDoubling
    {
        class AllReduce
        {
        public:
            AllReduce(Communicator const &communicator, void *buffer,
                size_type const sizeByte);
            AllReduce(const AllReduce &) = delete;
            AllReduce(AllReduce &&) = delete;
            AllReduce &operator=(const AllReduce &) = delete;
            AllReduce &operator=(AllReduce &&) = delete;
            ~AllReduce() = default;

            template<typename T>
            bool execute(void *buffer, Operation op, size_type const count);

            template<typename T>
            bool execute(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);

            template<typename T>
            bool executeBit(void *buffer, Operation op, size_type const count);

            template<typename T>
            bool executeBit(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);

        private:
            // Domain reduction
            bool mDomainRoot = false;
            std::vector<pMR::Connection> mDomainConnections;
            std::vector<unsigned char, pMR::Allocator<unsigned char>>
                mDomainBuffers;
            std::vector<pMR::SendMemoryWindow> mDomainSendWindows;
            std::vector<pMR::RecvMemoryWindow> mDomainRecvWindows;
            // Pre Recursive-doubling reduction
            std::unique_ptr<pMR::Connection> mPreConnection;
            std::vector<unsigned char, pMR::Allocator<unsigned char>>
                mPreBuffer;
            std::unique_ptr<pMR::SendMemoryWindow> mPreSendWindow;
            std::unique_ptr<pMR::RecvMemoryWindow> mPreRecvWindow;
            // Recursive-doubling
            int mRDPartition = -1;
            std::vector<pMR::Connection> mRDConnections;
            std::vector<unsigned char, pMR::Allocator<unsigned char>>
                mRDBuffers;
            std::vector<pMR::SendMemoryWindow> mRDSendWindows;
            std::vector<pMR::RecvMemoryWindow> mRDRecvWindows;

            void initWindows();
            template<typename T>
            void domainReduce(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);
            template<typename T>
            void preReduce(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);
            template<typename T>
            void recursiveDoubling(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);
            template<typename T>
            void reduceBroadcast(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);
            void postBroadcast();
            void domainBroadcast();
        };
    }
}

template<typename T>
bool pMR::RecursiveDoubling::AllReduce::execute(
    void *buffer, Operation op, size_type const count)
{
    switch(op)
    {
        case Operation::Max:
            return {execute<T>(buffer, &max, count)};
            break;
        case Operation::Min:
            return {execute<T>(buffer, &min, count)};
            break;
        case Operation::Sum:
            return {execute<T>(buffer, &sum, count)};
            break;
        case Operation::Prod:
            return {execute<T>(buffer, &prod, count)};
            break;
        default:
            return {false};
            break;
    }
}

template<typename T>
bool pMR::RecursiveDoubling::AllReduce::execute(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    initWindows();
    domainReduce(buffer, op, count);
    preReduce(buffer, op, count);

    recursiveDoubling(buffer, op, count);

    postBroadcast();
    domainBroadcast();

    return {true};
}

template<typename T>
bool pMR::RecursiveDoubling::AllReduce::executeBit(
    void *buffer, Operation op, size_type const count)
{
    switch(op)
    {
        case Operation::Max:
            return {executeBit<T>(buffer, &max, count)};
            break;
        case Operation::Min:
            return {executeBit<T>(buffer, &min, count)};
            break;
        case Operation::Sum:
            return {executeBit<T>(buffer, &sum, count)};
            break;
        case Operation::Prod:
            return {executeBit<T>(buffer, &prod, count)};
            break;
        default:
            return {false};
            break;
    }
}

template<typename T>
bool pMR::RecursiveDoubling::AllReduce::executeBit(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    initWindows();
    domainReduce(buffer, op, count);
    preReduce(buffer, op, count);

    reduceBroadcast(buffer, op, count);

    postBroadcast();
    domainBroadcast();

    return {true};
}

template<typename T>
void pMR::RecursiveDoubling::AllReduce::domainReduce(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    if(mDomainRoot)
    {
        for(auto &window : mDomainRecvWindows)
        {
            window.post();
            window.wait();
            op(reinterpret_cast<T const *>(window.data()),
                reinterpret_cast<T *>(buffer), count);
        }
    }
    else
    {
        for(auto &window : mDomainSendWindows)
        {
            window.post();
            window.wait();
        }
    }
}

template<typename T>
void pMR::RecursiveDoubling::AllReduce::preReduce(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    if(mPreConnection)
    {
        if(mRDConnections.size() == 0)
        {
            mPreSendWindow->post();
            mPreSendWindow->wait();
        }
        else
        {
            mPreRecvWindow->post();
            mPreRecvWindow->wait();
            op(reinterpret_cast<T const *>(mPreRecvWindow->data()),
                reinterpret_cast<T *>(buffer), count);
        }
    }
}

template<typename T>
void pMR::RecursiveDoubling::AllReduce::recursiveDoubling(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    auto sendWindow = mRDSendWindows.begin();
    auto recvWindow = mRDRecvWindows.begin();
    while(sendWindow != mRDSendWindows.end() &&
        recvWindow != mRDRecvWindows.end())
    {
        sendWindow->post();
        recvWindow->post();
        sendWindow->wait();
        recvWindow->wait();
        op(reinterpret_cast<T const *>(recvWindow->data()),
            reinterpret_cast<T *>(buffer), count);
        ++sendWindow;
        ++recvWindow;
    }
}

template<typename T>
void pMR::RecursiveDoubling::AllReduce::reduceBroadcast(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    if(mRDPartition >= 0)
    {
        // Reduce
        auto recvWindow = mRDRecvWindows.end();
        while(recvWindow != mRDRecvWindows.begin() + mRDPartition)
        {
            --recvWindow;
            recvWindow->post();
            recvWindow->wait();
            op(reinterpret_cast<T const *>(recvWindow->data()),
                reinterpret_cast<T *>(buffer), count);
        }
        if(mRDPartition != 0)
        {
            mRDSendWindows[mRDPartition - 1].post();
            mRDSendWindows[mRDPartition - 1].wait();

            // Broadcast
            mRDRecvWindows[mRDPartition - 1].post();
            mRDRecvWindows[mRDPartition - 1].wait();
            std::memcpy(buffer, mRDRecvWindows[mRDPartition - 1].data(),
                sizeof(T) * count);
        }
        auto sendWindow = mRDSendWindows.begin() + mRDPartition;
        while(sendWindow != mRDSendWindows.end())
        {
            sendWindow->post();
            sendWindow->wait();
            ++sendWindow;
        }
    }
}

#endif // pMR_ALLREDUCE_RECURSIVE_DOUBLING_ALLREDUCE_H
<commit_msg>Add const<commit_after>//  Copyright 2016 Peter Georg
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#ifndef pMR_ALLREDUCE_RECURSIVE_DOUBLING_ALLREDUCE_H
#define pMR_ALLREDUCE_RECURSIVE_DOUBLING_ALLREDUCE_H

#include <cstring>
#include "../../communicator.hpp"
#include "../../connection.hpp"
#include "../../misc/allocator.hpp"
#include "../../operations.hpp"
#include "../../recvmemorywindow.hpp"
#include "../../sendmemorywindow.hpp"

namespace pMR
{
    namespace RecursiveDoubling
    {
        class AllReduce
        {
        public:
            AllReduce(Communicator const &communicator, void *buffer,
                size_type const sizeByte);
            AllReduce(const AllReduce &) = delete;
            AllReduce(AllReduce &&) = delete;
            AllReduce &operator=(const AllReduce &) = delete;
            AllReduce &operator=(AllReduce &&) = delete;
            ~AllReduce() = default;

            template<typename T>
            bool execute(
                void *buffer, Operation const op, size_type const count);

            template<typename T>
            bool execute(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);

            template<typename T>
            bool executeBit(
                void *buffer, Operation const op, size_type const count);

            template<typename T>
            bool executeBit(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);

        private:
            // Domain reduction
            bool mDomainRoot = false;
            std::vector<pMR::Connection> mDomainConnections;
            std::vector<unsigned char, pMR::Allocator<unsigned char>>
                mDomainBuffers;
            std::vector<pMR::SendMemoryWindow> mDomainSendWindows;
            std::vector<pMR::RecvMemoryWindow> mDomainRecvWindows;
            // Pre Recursive-doubling reduction
            std::unique_ptr<pMR::Connection> mPreConnection;
            std::vector<unsigned char, pMR::Allocator<unsigned char>>
                mPreBuffer;
            std::unique_ptr<pMR::SendMemoryWindow> mPreSendWindow;
            std::unique_ptr<pMR::RecvMemoryWindow> mPreRecvWindow;
            // Recursive-doubling
            int mRDPartition = -1;
            std::vector<pMR::Connection> mRDConnections;
            std::vector<unsigned char, pMR::Allocator<unsigned char>>
                mRDBuffers;
            std::vector<pMR::SendMemoryWindow> mRDSendWindows;
            std::vector<pMR::RecvMemoryWindow> mRDRecvWindows;

            void initWindows();
            template<typename T>
            void domainReduce(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);
            template<typename T>
            void preReduce(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);
            template<typename T>
            void recursiveDoubling(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);
            template<typename T>
            void reduceBroadcast(void *buffer,
                void (*op)(T const *in, T *inout, size_type const count),
                size_type const count);
            void postBroadcast();
            void domainBroadcast();
        };
    }
}

template<typename T>
bool pMR::RecursiveDoubling::AllReduce::execute(
    void *buffer, Operation const op, size_type const count)
{
    switch(op)
    {
        case Operation::Max:
            return {execute<T>(buffer, &max, count)};
            break;
        case Operation::Min:
            return {execute<T>(buffer, &min, count)};
            break;
        case Operation::Sum:
            return {execute<T>(buffer, &sum, count)};
            break;
        case Operation::Prod:
            return {execute<T>(buffer, &prod, count)};
            break;
        default:
            return {false};
            break;
    }
}

template<typename T>
bool pMR::RecursiveDoubling::AllReduce::execute(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    initWindows();
    domainReduce(buffer, op, count);
    preReduce(buffer, op, count);

    recursiveDoubling(buffer, op, count);

    postBroadcast();
    domainBroadcast();

    return {true};
}

template<typename T>
bool pMR::RecursiveDoubling::AllReduce::executeBit(
    void *buffer, Operation const op, size_type const count)
{
    switch(op)
    {
        case Operation::Max:
            return {executeBit<T>(buffer, &max, count)};
            break;
        case Operation::Min:
            return {executeBit<T>(buffer, &min, count)};
            break;
        case Operation::Sum:
            return {executeBit<T>(buffer, &sum, count)};
            break;
        case Operation::Prod:
            return {executeBit<T>(buffer, &prod, count)};
            break;
        default:
            return {false};
            break;
    }
}

template<typename T>
bool pMR::RecursiveDoubling::AllReduce::executeBit(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    initWindows();
    domainReduce(buffer, op, count);
    preReduce(buffer, op, count);

    reduceBroadcast(buffer, op, count);

    postBroadcast();
    domainBroadcast();

    return {true};
}

template<typename T>
void pMR::RecursiveDoubling::AllReduce::domainReduce(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    if(mDomainRoot)
    {
        for(auto &window : mDomainRecvWindows)
        {
            window.post();
            window.wait();
            op(reinterpret_cast<T const *>(window.data()),
                reinterpret_cast<T *>(buffer), count);
        }
    }
    else
    {
        for(auto &window : mDomainSendWindows)
        {
            window.post();
            window.wait();
        }
    }
}

template<typename T>
void pMR::RecursiveDoubling::AllReduce::preReduce(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    if(mPreConnection)
    {
        if(mRDConnections.size() == 0)
        {
            mPreSendWindow->post();
            mPreSendWindow->wait();
        }
        else
        {
            mPreRecvWindow->post();
            mPreRecvWindow->wait();
            op(reinterpret_cast<T const *>(mPreRecvWindow->data()),
                reinterpret_cast<T *>(buffer), count);
        }
    }
}

template<typename T>
void pMR::RecursiveDoubling::AllReduce::recursiveDoubling(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    auto sendWindow = mRDSendWindows.begin();
    auto recvWindow = mRDRecvWindows.begin();
    while(sendWindow != mRDSendWindows.end() &&
        recvWindow != mRDRecvWindows.end())
    {
        sendWindow->post();
        recvWindow->post();
        sendWindow->wait();
        recvWindow->wait();
        op(reinterpret_cast<T const *>(recvWindow->data()),
            reinterpret_cast<T *>(buffer), count);
        ++sendWindow;
        ++recvWindow;
    }
}

template<typename T>
void pMR::RecursiveDoubling::AllReduce::reduceBroadcast(void *buffer,
    void (*op)(T const *in, T *inout, size_type const count),
    size_type const count)
{
    if(mRDPartition >= 0)
    {
        // Reduce
        auto recvWindow = mRDRecvWindows.end();
        while(recvWindow != mRDRecvWindows.begin() + mRDPartition)
        {
            --recvWindow;
            recvWindow->post();
            recvWindow->wait();
            op(reinterpret_cast<T const *>(recvWindow->data()),
                reinterpret_cast<T *>(buffer), count);
        }
        if(mRDPartition != 0)
        {
            mRDSendWindows[mRDPartition - 1].post();
            mRDSendWindows[mRDPartition - 1].wait();

            // Broadcast
            mRDRecvWindows[mRDPartition - 1].post();
            mRDRecvWindows[mRDPartition - 1].wait();
            std::memcpy(buffer, mRDRecvWindows[mRDPartition - 1].data(),
                sizeof(T) * count);
        }
        auto sendWindow = mRDSendWindows.begin() + mRDPartition;
        while(sendWindow != mRDSendWindows.end())
        {
            sendWindow->post();
            sendWindow->wait();
            ++sendWindow;
        }
    }
}

#endif // pMR_ALLREDUCE_RECURSIVE_DOUBLING_ALLREDUCE_H
<|endoftext|>


<commit_before>#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <GLFW/glfw3.h>

#include "graphics/gatherer_graphics.h"
#include "GLContextWindow.h"
#include "OGLESGPGPUTest.h"

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#include <iostream>

int main(int argc, char **argv)
{
    cv::VideoCapture capture(0);
    cv::Size size(int(capture.get(cv::CAP_PROP_FRAME_WIDTH)), int(capture.get(cv::CAP_PROP_FRAME_HEIGHT)));

    //size = size / 4;

    // Create the context
    gatherer::graphics::GLContextWindow window(size, "display");
    gatherer::graphics::OEGLGPGPUTest test(&window, window.getResolution().x);

    while( /*capture */ true )
    {
        cv::Mat frame;
        capture >> frame;
        cv::resize(frame, frame, size);
        cv::cvtColor(frame, frame, cv::COLOR_BGR2BGRA);
        test.captureOutput(frame.size(), frame.ptr(), true);
        window.swapBuffers();
    }
}
<commit_msg>updated ogles_gpgpu_test to use full captureOutput call<commit_after>#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <GLFW/glfw3.h>

#include "graphics/gatherer_graphics.h"
#include "GLContextWindow.h"
#include "OGLESGPGPUTest.h"

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#include <iostream>

int main(int argc, char **argv)
{
    cv::VideoCapture capture(0);
    cv::Size size(int(capture.get(cv::CAP_PROP_FRAME_WIDTH)), int(capture.get(cv::CAP_PROP_FRAME_HEIGHT)));

    //size = size / 4;

    // Create the context
    gatherer::graphics::GLContextWindow window(size, "display");
    gatherer::graphics::OEGLGPGPUTest test(&window, window.getResolution().x);
    test.setDoDisplay(true);

    while( /*capture */ true )
    {
        cv::Mat frame;
        capture >> frame;
        cv::resize(frame, frame, size);
        cv::cvtColor(frame, frame, cv::COLOR_BGR2BGRA);
        test.captureOutput(frame.size(), frame.ptr(), true, 0, GL_BGRA);
        window.swapBuffers();
    }
}
<|endoftext|>


<commit_before>/** @file
 *
 * @ingroup dspSoundFileLib
 *
 * @brief Provides a common interface to soundfile data
 *
 * @details This object provides a common set of attributes and methods for working with soundfiles at a specific filepath.
 * This allows us to access metadata and copy values in a common way without duplicating code. As with the rest of the
 * SoundfileLib, it relies on the third-party libsndfile library.
 *
 * @authors Nathan Wolek
 *
 * @copyright Copyright © 2013 by Nathan Wolek @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTSoundfile.h"

TTObjectBasePtr TTSoundfile::instantiate(TTSymbol& name, TTValue& arguments)
{
	return new TTSoundfile(arguments);
}

extern "C" void TTSoundfile::registerClass()
{
	TTClassRegister(thisTTClassName, thisTTClassTags, TTSoundfile::instantiate);
}

TT_AUDIO_CONSTRUCTOR,
mFilePath(kTTSymEmpty),
mTitle(kTTSymEmpty),
mAnnotation(kTTSymEmpty),
mArtist(kTTSymEmpty),
mDate(kTTSymEmpty),
mSoundFile(NULL),
mDuration(0.0),
mNumChannels(0)
{
	// add the attributes and messages here

	//* Send a file path to the object and attempt to load the file *//
	TTErr setFilePath(const TTValue& value);
}

TTSoundfile::~TTSoundfile()
{
	// copied from TTSoundfilePlayer, confirm that it is needed
	if (mSoundFile)
		sf_close(mSoundFile);
}

TTErr TTSoundfile::setFilePath(const TTValue& newValue)
{
	TTSymbol	potentialFilePath = newValue;
	SNDFILE*	soundfile;
	const char*	textInfo;
#ifdef TT_PLATFORM_WIN
	// There is a bug in libsndfile on Windows where upon return from this function a runtime check fails
	// because the stack is corrupted around soundfileInfo when sf_open() is called.
	// We work around this by allocating some extra memory to absorb the overrun.
    // [tap - old comment from soundfileplayer]
	SF_INFO		soundfileInfo[2];
#else
	SF_INFO		soundfileInfo[1];
#endif

	memset(&soundfileInfo, 0, sizeof(SF_INFO));
	//soundfileInfo.format = 0;
	soundfile = sf_open(potentialFilePath.c_str(), SFM_READ, soundfileInfo);

	if (soundfile) { // if the filepath was valid

		// swap out the old for the new, but hold onto the old for a moment
		SNDFILE* oldSoundFile = mSoundFile;
		mSoundFile = soundfile;

		// if there was an old file, we can now close it
		if (oldSoundFile)
			sf_close(oldSoundFile);

		// copy the metadata to our local variable
		memcpy(&mSoundFileInfo, soundfileInfo, sizeof(SF_INFO));

		/* copy additional data to local variables */
        // filepath
		mFilePath = potentialFilePath;

        // number of channels
        mNumChannels = mSoundFileInfo.channels;

        // sample rate
        mSampleRate = mSoundFileInfo.samplerate;

        // duration in samples
		mDurationInSamples = mSoundFileInfo.frames;

        // duration in seconds
		mDurationInSeconds = mDurationInSamples / mSampleRate;

		// copy specific metadata pieces to separate TTSymbols
		// in transfer from player, made this little pattern into a macro
            #define SF_STRING_TO_TTSYMBOL(sf_info_piece, local_ttsymbol) \
                textInfo = sf_get_string(soundfile, sf_info_piece); \
                if (textInfo) local_ttsymbol = TT(textInfo); \
                else local_ttsymbol = kTTSymEmpty;

		// title
		SF_STRING_TO_TTSYMBOL(SF_STR_TITLE, mTitle);
		// artist
		SF_STRING_TO_TTSYMBOL(SF_STR_ARTIST, mArtist);
		// date
		SF_STRING_TO_TTSYMBOL(SF_STR_DATE, mDate);
        // comment
		SF_STRING_TO_TTSYMBOL(SF_STR_COMMENT, mAnnotation);

		return kTTErrNone;

	} else { // if the filepath was invalid
		char errstr[256];
		sf_error_str(soundfile, errstr, 256);
		TTLogMessage("cannot open soundfile %s: %s", potentialFilePath.c_str(), errstr);
		return kTTErrInvalidValue;
	}

}
<commit_msg>still building out the interface, but stopping for dinner<commit_after>/** @file
 *
 * @ingroup dspSoundFileLib
 *
 * @brief Provides a common interface to soundfile data
 *
 * @details This object provides a common set of attributes and methods for working with soundfiles at a specific filepath.
 * This allows us to access metadata and copy values in a common way without duplicating code. As with the rest of the
 * SoundfileLib, it relies on the third-party libsndfile library.
 *
 * @authors Nathan Wolek
 *
 * @copyright Copyright © 2013 by Nathan Wolek @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTSoundfile.h"

TTObjectBasePtr TTSoundfile::instantiate(TTSymbol& name, TTValue& arguments)
{
	return new TTSoundfile(arguments);
}

extern "C" void TTSoundfile::registerClass()
{
	TTClassRegister(thisTTClassName, thisTTClassTags, TTSoundfile::instantiate);
}

TT_AUDIO_CONSTRUCTOR,
mFilePath(kTTSymEmpty),
mNumChannels(0),
mSampleRate(0.0),
mDurationInSamples(0),
mDurationInSeconds(0.0),
mTitle(kTTSymEmpty),
mArtist(kTTSymEmpty),
mDate(kTTSymEmpty),
mAnnotation(kTTSymEmpty),
mSoundFile(NULL),
mSoundFileInfo(NULL)
{
	// add the attributes and messages here
    addAttributeWithSetter(FilePath, kTypeSymbol);
    addAttribute(NumChannels, kTypeInt16);
        addAttributeProperty(NumChannels, readOnly, kTTBoolYes);
    // need to add the rest of these here...

    addAttribute(DurationInSeconds, kTypeFloat64);
        addAttributeProperty(DurationInSeconds, readOnly, kTTBoolYes);

	//* Send a file path to the object and attempt to load the file *//
	TTErr setFilePath(const TTValue& value);
}

TTSoundfile::~TTSoundfile()
{
	// copied from TTSoundfilePlayer, confirm that it is needed
	if (mSoundFile)
		sf_close(mSoundFile);
}

TTErr TTSoundfile::setFilePath(const TTValue& newValue)
{
	TTSymbol	potentialFilePath = newValue;
	SNDFILE*	soundfile;
	const char*	textInfo;
#ifdef TT_PLATFORM_WIN
	// There is a bug in libsndfile on Windows where upon return from this function a runtime check fails
	// because the stack is corrupted around soundfileInfo when sf_open() is called.
	// We work around this by allocating some extra memory to absorb the overrun.
    // [tap - old comment from soundfileplayer]
	SF_INFO		soundfileInfo[2];
#else
	SF_INFO		soundfileInfo[1];
#endif

	memset(&soundfileInfo, 0, sizeof(SF_INFO));
	//soundfileInfo.format = 0;
	soundfile = sf_open(potentialFilePath.c_str(), SFM_READ, soundfileInfo);

	if (soundfile) { // if the filepath was valid

		// swap out the old for the new, but hold onto the old for a moment
		SNDFILE* oldSoundFile = mSoundFile;
		mSoundFile = soundfile;

		// if there was an old file, we can now close it
		if (oldSoundFile)
			sf_close(oldSoundFile);

		// copy the metadata to our local variable
		memcpy(&mSoundFileInfo, soundfileInfo, sizeof(SF_INFO));

		/* copy additional data to local variables */
        // filepath
		mFilePath = potentialFilePath;

        // number of channels
        mNumChannels = mSoundFileInfo.channels;

        // sample rate
        mSampleRate = mSoundFileInfo.samplerate;

        // duration in samples
		mDurationInSamples = mSoundFileInfo.frames;

        // duration in seconds
		mDurationInSeconds = mDurationInSamples / mSampleRate;

		// copy specific metadata pieces to separate TTSymbols
		// in transfer from player, made this little pattern into a macro
            #define SF_STRING_TO_TTSYMBOL(sf_info_piece, local_ttsymbol) \
                textInfo = sf_get_string(soundfile, sf_info_piece); \
                if (textInfo) local_ttsymbol = TT(textInfo); \
                else local_ttsymbol = kTTSymEmpty;

		// title
		SF_STRING_TO_TTSYMBOL(SF_STR_TITLE, mTitle);
		// artist
		SF_STRING_TO_TTSYMBOL(SF_STR_ARTIST, mArtist);
		// date
		SF_STRING_TO_TTSYMBOL(SF_STR_DATE, mDate);
        // comment
		SF_STRING_TO_TTSYMBOL(SF_STR_COMMENT, mAnnotation);

		return kTTErrNone;

	} else { // if the filepath was invalid
		char errstr[256];
		sf_error_str(soundfile, errstr, 256);
		TTLogMessage("cannot open soundfile %s: %s", potentialFilePath.c_str(), errstr);

		return kTTErrInvalidValue;

	}

}
<|endoftext|>


<commit_before>#include "OE/Graphics/API/Texture.hpp"

#include "OE/Config.hpp"

#if OE_WINDOWS
	#include <OE/Platform/Windows/Windows.hpp>
#elif OE_ANDROID
	#include <OE/Platform/Android/Android.hpp>
#endif

#include "OE/System/File.hpp"
#include "OE/Graphics/FreeImage.hpp"
#include "OE/Application/Context.hpp"
#include "OE/Misc/Log.hpp"

#if OE_OPENGL_ANY
	#include "OE/Platform/OpenGL/GLTexture.hpp"
#endif
#if OE_D3D
	#include "OE/Platform/Direct3D/D3DTexture.hpp"
#endif

namespace OrbitEngine { namespace Graphics {

	Texture* Texture::Create(TextureProperties& properties, std::vector<void*> data)
	{
		OE_LOG_DEBUG("Creating texture: format: " << properties.formatProperties.format << ", size: " << properties.width << "x" << properties.height);

		switch (Application::Context::GetCurrentAPI()) {
#if OE_OPENGL_ANY
		case OPENGL:
#if OE_OPENGL_ES
		case OPENGL_ES:
#endif
			return new GLTexture(properties, data);
#endif
#if OE_D3D
		case DIRECT3D:
			return new D3DTexture(properties, data);
#endif
		}

		OE_ASSERT(false);
		return nullptr;
	}

	Texture* Texture::Create(TextureProperties& properties, void* data)
	{
		std::vector<void*> v(1);
		v[0] = data;
		return Create(properties, v);
	}

	Texture* Texture::Load(std::vector<std::string> files, TextureSampleProperties& sampleProperties)
	{
		if (files.size() == 0) {
			OE_LOG_WARNING("Files size can't be zero.");
			return nullptr;
		}

		TextureProperties properties;
		properties.sampleProperties = sampleProperties;
		std::vector<void*> dataPtrs;

		unsigned int w, h, bpp;

		for (size_t i = 0; i < files.size(); i++) {
			bool f32b = false;
#if OE_D3D
			// DirectX11 doesn't support 24bit textures, force 32bit
			f32b = Application::Context::GetCurrentAPI() == DIRECT3D;
#endif
			void* data = ReadImage(files[i], w, h, bpp, f32b); // We assume formats will match

			switch (bpp) {
			case 8:
				properties.formatProperties.format = R8;
				break;
			case 16:
				properties.formatProperties.format = R16;
				break;
			case 24:
				properties.formatProperties.format = RGB;
				break;
			case 32:
				properties.formatProperties.format = RGBA;
				break;
			case 96:
				properties.formatProperties.format = RGB32F;
				properties.formatProperties.dataType = FLOAT;
				break;
			default:
				OE_LOG_WARNING("Unsupported bit depth in " << files[i]);
				continue;
			}

			if (data == 0)
				return 0;
			dataPtrs.push_back(data);
		}

		properties.width = w;
		properties.height = h;

		Texture* t = Create(properties, dataPtrs);

		for (size_t i = 0; i < dataPtrs.size(); i++)
			delete dataPtrs[i];

		return t;
	}

	Texture* Texture::Load(std::string file, TextureSampleProperties& sampleProperties)
	{
		std::vector<std::string> v(1);
		v[0] = file;
		return Load(v, sampleProperties);
	}

	Texture* Texture::Load(std::string file)
	{
		TextureSampleProperties sampleProperties;
		return Load(file, sampleProperties);
	}

	Texture* Texture::Load(std::vector<std::string> files)
	{
		TextureSampleProperties sampleProperties;
		return Load(files, sampleProperties);
	}

	void Texture::Unbind(const unsigned int slot)
	{
		switch (Application::Context::GetCurrentAPI()) {
#if OE_OPENGL_ANY
		case OPENGL:
#if OE_OPENGL_ES
		case OPENGL_ES:
#endif
			GLTexture::Unbind(slot);
			break;
#endif
#if OE_D3D
		case DIRECT3D:
			//D3DTexture::Unbind(slot);
			break;
#endif
		}
	}

	unsigned int Texture::CalculateMipLevelsCount(unsigned int width, unsigned int height)
	{
		unsigned int mips = 1;

		while (width > 1 && height > 1)
		{
			width = std::max(width / 2, 1u);
			height = std::max(height / 2, 1u);
			++mips;
		}

		return mips;
	}

	unsigned int Texture::BPPFromFormat(TextureFormat format)
	{
		switch (format) {
		case R8:
			return 8;
		case R16:
		case RG8:
			return 16;
		case RGB:
		case RGB8:
			return 24;
		case RGBA:
		case RGBA8:
			return 32;
		case RG32F:
			return 64;
		case RGB32F:
			return 96;
		default:
			OE_LOG_WARNING("BPP not set for format!");
			return 0;
		}

	}

	Texture::Texture(TextureProperties properties)
		: m_Properties(properties)
	{
		//ResourcesManager::RegisterTexture(this);

		if (m_Properties.sampleProperties.mipmapping)
			m_MipLevels = CalculateMipLevelsCount(m_Properties.width, m_Properties.height);
	}

	Texture::~Texture()
	{
		//ResourcesManager::UnregisterTexture(this);
	}

} }<commit_msg>fix leak in texture loading<commit_after>#include "OE/Graphics/API/Texture.hpp"

#include "OE/Config.hpp"

#if OE_WINDOWS
	#include <OE/Platform/Windows/Windows.hpp>
#elif OE_ANDROID
	#include <OE/Platform/Android/Android.hpp>
#endif

#include "OE/System/File.hpp"
#include "OE/Graphics/FreeImage.hpp"
#include "OE/Application/Context.hpp"
#include "OE/Misc/Log.hpp"

#if OE_OPENGL_ANY
	#include "OE/Platform/OpenGL/GLTexture.hpp"
#endif
#if OE_D3D
	#include "OE/Platform/Direct3D/D3DTexture.hpp"
#endif

namespace OrbitEngine { namespace Graphics {

	Texture* Texture::Create(TextureProperties& properties, std::vector<void*> data)
	{
		OE_LOG_DEBUG("Creating texture: format: " << properties.formatProperties.format << ", size: " << properties.width << "x" << properties.height);

		switch (Application::Context::GetCurrentAPI()) {
#if OE_OPENGL_ANY
		case OPENGL:
#if OE_OPENGL_ES
		case OPENGL_ES:
#endif
			return new GLTexture(properties, data);
#endif
#if OE_D3D
		case DIRECT3D:
			return new D3DTexture(properties, data);
#endif
		}

		OE_ASSERT(false);
		return nullptr;
	}

	Texture* Texture::Create(TextureProperties& properties, void* data)
	{
		std::vector<void*> v(1);
		v[0] = data;
		return Create(properties, v);
	}

	Texture* Texture::Load(std::vector<std::string> files, TextureSampleProperties& sampleProperties)
	{
		if (files.size() == 0) {
			OE_LOG_WARNING("Files size can't be zero.");
			return nullptr;
		}

		TextureProperties properties;
		properties.sampleProperties = sampleProperties;
		std::vector<void*> dataPtrs;

		unsigned int w, h, bpp;

		for (size_t i = 0; i < files.size(); i++) {
			bool f32b = false;
#if OE_D3D
			// DirectX11 doesn't support 24bit textures, force 32bit
			f32b = Application::Context::GetCurrentAPI() == DIRECT3D;
#endif
			void* data = ReadImage(files[i], w, h, bpp, f32b); // We assume formats will match

			switch (bpp) {
			case 8:
				properties.formatProperties.format = R8;
				break;
			case 16:
				properties.formatProperties.format = R16;
				break;
			case 24:
				properties.formatProperties.format = RGB;
				break;
			case 32:
				properties.formatProperties.format = RGBA;
				break;
			case 96:
				properties.formatProperties.format = RGB32F;
				properties.formatProperties.dataType = FLOAT;
				break;
			default:
				OE_LOG_WARNING("Unsupported bit depth in " << files[i]);
				continue;
			}

			if (data == 0) {
				for (size_t i = 0; i < dataPtrs.size(); i++)
					delete dataPtrs[i];
				return 0;
			}
			dataPtrs.push_back(data);
		}

		properties.width = w;
		properties.height = h;

		Texture* t = Create(properties, dataPtrs);

		for (size_t i = 0; i < dataPtrs.size(); i++)
			delete dataPtrs[i];

		return t;
	}

	Texture* Texture::Load(std::string file, TextureSampleProperties& sampleProperties)
	{
		std::vector<std::string> v(1);
		v[0] = file;
		return Load(v, sampleProperties);
	}

	Texture* Texture::Load(std::string file)
	{
		TextureSampleProperties sampleProperties;
		return Load(file, sampleProperties);
	}

	Texture* Texture::Load(std::vector<std::string> files)
	{
		TextureSampleProperties sampleProperties;
		return Load(files, sampleProperties);
	}

	void Texture::Unbind(const unsigned int slot)
	{
		switch (Application::Context::GetCurrentAPI()) {
#if OE_OPENGL_ANY
		case OPENGL:
#if OE_OPENGL_ES
		case OPENGL_ES:
#endif
			GLTexture::Unbind(slot);
			break;
#endif
#if OE_D3D
		case DIRECT3D:
			//D3DTexture::Unbind(slot);
			break;
#endif
		}
	}

	unsigned int Texture::CalculateMipLevelsCount(unsigned int width, unsigned int height)
	{
		unsigned int mips = 1;

		while (width > 1 && height > 1)
		{
			width = std::max(width / 2, 1u);
			height = std::max(height / 2, 1u);
			++mips;
		}

		return mips;
	}

	unsigned int Texture::BPPFromFormat(TextureFormat format)
	{
		switch (format) {
		case R8:
			return 8;
		case R16:
		case RG8:
			return 16;
		case RGB:
		case RGB8:
			return 24;
		case RGBA:
		case RGBA8:
			return 32;
		case RG32F:
			return 64;
		case RGB32F:
			return 96;
		default:
			OE_LOG_WARNING("BPP not set for format!");
			return 0;
		}

	}

	Texture::Texture(TextureProperties properties)
		: m_Properties(properties)
	{
		//ResourcesManager::RegisterTexture(this);

		if (m_Properties.sampleProperties.mipmapping)
			m_MipLevels = CalculateMipLevelsCount(m_Properties.width, m_Properties.height);
	}

	Texture::~Texture()
	{
		//ResourcesManager::UnregisterTexture(this);
	}

} }<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <list>

#include "mfxloader.h"

namespace MFX {

static bool parseGUID(const char* src, mfxPluginUID* uid)
{
    mfxPluginUID plugin_uid{};
    mfxU8* p = uid->Data;

    int res = sscanf(src,
        "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
        p, p + 1, p + 2, p + 3, p + 4, p + 5, p + 6, p + 7,
        p + 8, p + 9, p + 10, p + 11, p + 12, p + 13, p + 14, p + 15);

    if (res != sizeof(uid)) {
        return false;
    }

    *uid = plugin_uid;
    return true;
}

void PluginInfo::Load(char* name, char* value)
{
#ifdef LINUX64
    #define FIELD_FileName "FileName64"
#else
    #define FIELD_FileName "FileName32"
#endif

    if (!strcmp(name, "Type")) {
        Type = atoi(value);
        m_parsed |= PARSED_TYPE;
    } else if (!strcmp(name, "CodecID")) {
        const int fourccLen = 4;
        if (strlen(value) == 0 || strlen(value) > fourccLen)
            return;

        CodecId = MFX_MAKEFOURCC(' ',' ',' ',' ');
        char* id = reinterpret_cast<char*>(&CodecId);
        for (size_t i = 0; i < strlen(value); ++i)
            id[i] = value[i];

        m_parsed |= PARSED_CODEC_ID;
    } else if (!strcmp(name, "GUID")) {
        if (!parseGUID(value, &PluginUID))
            return;

        m_parsed |= PARSED_UID;
    } else if (!strcmp(name, "Path") || !strcmp(name, FIELD_FileName)) {
        // strip quotes
        char* p = value + strlen(value) - 1;
        if (*value == '"' && *p == '"') {
            *p = '\0';
            ++value;
        }
        if (strlen(m_path) + strlen("/") + strlen(value) >= PATH_MAX)
            return;
        strcpy(m_path + strlen(m_path), "/"); // TODO: looks to be wrong
        strcpy(m_path + strlen(m_path), value);
        m_parsed |= PARSED_PATH;
    } else if (0 == strcmp(name, "Default")) {
        m_default = (0 != atoi(value));
        m_parsed |= PARSED_DEFAULT;
    } else if (0 == strcmp(name, "PluginVersion")) {
        PluginVersion = atoi(value);
        m_parsed |= PARSED_VERSION;
    } else if (0 == strcmp(name, "APIVersion")) {
        APIVersion.Version = atoi(value);
        m_parsed |= PARSED_API_VERSION;
    }
}

void PluginInfo::Print()
{
  printf("[%s]\n", printUID(PluginUID).c_str());
  printf("  GUID=%s\n", printUID(PluginUID).c_str());
  printf("  PluginVersion=%d\n", PluginVersion);
  printf("  APIVersion=%d\n", APIVersion.Version);
  printf("  Path=%s\n", m_path);
  printf("  Type=%d\n", Type);
  printf("  CodecID=%s\n", printCodecId(CodecId).c_str());
  printf("  Default=%d\n", m_default);
}

// strip tailing spaces
static inline char* strip(char* s)
{
    char* p = s + strlen(s);
    while (p > s && isspace(*--p)) *p = 0;
    return s;
}

// skip initial spaces
static inline char* skip(char* s)
{
    while (*s && isspace(*s)) ++s;
    return s;
}

void parse(const char* file_name, std::list<PluginInfo>& plugins)
{
  char line[PATH_MAX];
  PluginInfo plg;

  FILE* file = fopen(file_name, "r");
  if (!file)
    return;

  while(fgets(line, PATH_MAX, file)) {
    char* p = skip(line);

    if (strchr(";#", *p)) {
      // skip comments
    } else if (*p == '[') {
      if (plg.isValid()) {
        plugins.push_back(std::move(plg));
        plg = PluginInfo{};
      }
    } else {
      char* name = p;
      char* value = p;

      while(*value && !strchr("=:;#", *value)) ++value;
      if (*value && strchr("=:", *value)) {
        *value++ = '\0';
      }

      p = value;
      while (*p && !strchr(";#", *p)) ++p;
      if (*p != '\0') {
        *p = '\0';
      }

      name = strip(name);
      value = skip(strip(value));

      if (*name != '\0' && *value != '\0') {
        plg.Load(name, value);
      }
    }
  }
  fclose(file);

  //print(plugins); // for debug
}

} // namespace MFX
<commit_msg>[mfx_dispatch] Fix the last plugin in plugins.cfg not being parsed<commit_after>// Copyright (c) 2017-2018 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <list>

#include "mfxloader.h"

namespace MFX {

static bool parseGUID(const char* src, mfxPluginUID* uid)
{
    mfxPluginUID plugin_uid{};
    mfxU8* p = uid->Data;

    int res = sscanf(src,
        "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
        p, p + 1, p + 2, p + 3, p + 4, p + 5, p + 6, p + 7,
        p + 8, p + 9, p + 10, p + 11, p + 12, p + 13, p + 14, p + 15);

    if (res != sizeof(uid)) {
        return false;
    }

    *uid = plugin_uid;
    return true;
}

void PluginInfo::Load(char* name, char* value)
{
#ifdef LINUX64
    #define FIELD_FileName "FileName64"
#else
    #define FIELD_FileName "FileName32"
#endif

    if (!strcmp(name, "Type")) {
        Type = atoi(value);
        m_parsed |= PARSED_TYPE;
    } else if (!strcmp(name, "CodecID")) {
        const int fourccLen = 4;
        if (strlen(value) == 0 || strlen(value) > fourccLen)
            return;

        CodecId = MFX_MAKEFOURCC(' ',' ',' ',' ');
        char* id = reinterpret_cast<char*>(&CodecId);
        for (size_t i = 0; i < strlen(value); ++i)
            id[i] = value[i];

        m_parsed |= PARSED_CODEC_ID;
    } else if (!strcmp(name, "GUID")) {
        if (!parseGUID(value, &PluginUID))
            return;

        m_parsed |= PARSED_UID;
    } else if (!strcmp(name, "Path") || !strcmp(name, FIELD_FileName)) {
        // strip quotes
        char* p = value + strlen(value) - 1;
        if (*value == '"' && *p == '"') {
            *p = '\0';
            ++value;
        }
        if (strlen(m_path) + strlen("/") + strlen(value) >= PATH_MAX)
            return;
        strcpy(m_path + strlen(m_path), "/"); // TODO: looks to be wrong
        strcpy(m_path + strlen(m_path), value);
        m_parsed |= PARSED_PATH;
    } else if (0 == strcmp(name, "Default")) {
        m_default = (0 != atoi(value));
        m_parsed |= PARSED_DEFAULT;
    } else if (0 == strcmp(name, "PluginVersion")) {
        PluginVersion = atoi(value);
        m_parsed |= PARSED_VERSION;
    } else if (0 == strcmp(name, "APIVersion")) {
        APIVersion.Version = atoi(value);
        m_parsed |= PARSED_API_VERSION;
    }
}

void PluginInfo::Print()
{
  printf("[%s]\n", printUID(PluginUID).c_str());
  printf("  GUID=%s\n", printUID(PluginUID).c_str());
  printf("  PluginVersion=%d\n", PluginVersion);
  printf("  APIVersion=%d\n", APIVersion.Version);
  printf("  Path=%s\n", m_path);
  printf("  Type=%d\n", Type);
  printf("  CodecID=%s\n", printCodecId(CodecId).c_str());
  printf("  Default=%d\n", m_default);
}

// strip tailing spaces
static inline char* strip(char* s)
{
    char* p = s + strlen(s);
    while (p > s && isspace(*--p)) *p = 0;
    return s;
}

// skip initial spaces
static inline char* skip(char* s)
{
    while (*s && isspace(*s)) ++s;
    return s;
}

void parse(const char* file_name, std::list<PluginInfo>& plugins)
{
  char line[PATH_MAX];
  PluginInfo plg;

  FILE* file = fopen(file_name, "r");
  if (!file)
    return;

  while(fgets(line, PATH_MAX, file)) {
    char* p = skip(line);

    if (strchr(";#", *p)) {
      // skip comments
    } else if (*p == '[') {
      if (plg.isValid()) {
        plugins.push_back(std::move(plg));
        plg = PluginInfo{};
      }
    } else {
      char* name = p;
      char* value = p;

      while(*value && !strchr("=:;#", *value)) ++value;
      if (*value && strchr("=:", *value)) {
        *value++ = '\0';
      }

      p = value;
      while (*p && !strchr(";#", *p)) ++p;
      if (*p != '\0') {
        *p = '\0';
      }

      name = strip(name);
      value = skip(strip(value));

      if (*name != '\0' && *value != '\0') {
        plg.Load(name, value);
      }
    }
  }

  if (plg.isValid()) {
      plugins.push_back(std::move(plg));
  }

  fclose(file);

  //print(plugins); // for debug
}

} // namespace MFX
<|endoftext|>