<commit_before>#ifndef PROCESSO_H //include de guarda para evitar redefinicao da classe caso ela seja incluida em mais de um cpp
#define PROCESSO_H
#include <iostream>//para usar o std::cout e facilitar a impressao das informcoes na tela
//TODO: fazer metodo para calcular offset de memoria
class processo{
//Inicio da definicao das variaveis do processo
private:
	//Inicio da definicao da estrutura contida no arquivo processes.txt
	int tempo_inicializacao, tempo_processador;
	int prioridade;
	int blocos_em_memoria;
	bool requisicao_impressora,requisicao_scanner,requisicao_modem;
	int codigo_disco;
	//Fim da definicao da estrutura contida no arquivo processes.txt

	//Inicio da definicao de outras variaveis que devem aparecer na tela, mas nao estao no txt
		int Offset_da_memoria;//uma variavel que pode ser calculada
	/*
		Observacao: cada processo sera colocado em uma estrutura de vetor
		(std::vector). Logo, seu PID (ID do processo) pode ser entendido como
		o indice atual do vetor + 1 (+ 1, pois o PID comeca em 1 ). Por esse motivo,
		a classe processo nao possui a variavel PID
	*/
	//Fim da definicao de outras variaveis que devem aparecer na tela, mas nao estao no txt
//Fim da definicao das variaveis do processo

//Inicio da definicao dos metodos do processo

public:
	processo();//construtor sem argumentos de entrada permite nao precisar passar todos os argumentos da classe de uma vez
	//Inicio da declaracao dos setters
	void set_tempos(int,int);//tempos de inicializacao e de processador respectivamente
	void set_requisicoes(bool,bool,bool);//requisicoes de impressora,scanner e modem respectivamente
	void set_prioridade(int);
	void set_blocos_memoria(int);
	void set_codigo_disco(int);
	//Fim da declaracao dos setters

	//Inicio da declaracao dos getters
	int get_tempo_inicializacao();
	int get_tempo_processador();
	bool get_requisicao_impressora();
	bool get_requisicao_scanner();
	bool get_requisicao_modem();
	int get_prioridade();
	int get_blocos_memoria();
	int get_codigo_disco();
	//Fim da declaracao dos getters
	void imprime_infomacoes_processo(int);//sera passado a ele o PID
//Fim da definicao dos metodos do processo
};
#endif<commit_msg>Adição do atributo "início"<commit_after>#ifndef PROCESSO_H //include de guarda para evitar redefinicao da classe caso ela seja incluida em mais de um cpp
#define PROCESSO_H
#include <iostream>//para usar o std::cout e facilitar a impressao das informcoes na tela
//TODO: fazer metodo para calcular offset de memoria
class processo{
//Inicio da definicao das variaveis do processo
private:
	//Inicio da definicao da estrutura contida no arquivo processes.txt
	int tempo_inicializacao, tempo_processador;
	int prioridade;
	int blocos_em_memoria;
	int inicio;
	bool requisicao_impressora,requisicao_scanner,requisicao_modem;
	int codigo_disco;
	//Fim da definicao da estrutura contida no arquivo processes.txt

	//Inicio da definicao de outras variaveis que devem aparecer na tela, mas nao estao no txt
		int Offset_da_memoria;//uma variavel que pode ser calculada
	/*
		Observacao: cada processo sera colocado em uma estrutura de vetor
		(std::vector). Logo, seu PID (ID do processo) pode ser entendido como
		o indice atual do vetor + 1 (+ 1, pois o PID comeca em 1 ). Por esse motivo,
		a classe processo nao possui a variavel PID
	*/
	//Fim da definicao de outras variaveis que devem aparecer na tela, mas nao estao no txt
//Fim da definicao das variaveis do processo

//Inicio da definicao dos metodos do processo

public:
	processo();//construtor sem argumentos de entrada permite nao precisar passar todos os argumentos da classe de uma vez
	//Inicio da declaracao dos setters
	void set_tempos(int,int);//tempos de inicializacao e de processador respectivamente
	void set_requisicoes(bool,bool,bool);//requisicoes de impressora,scanner e modem respectivamente
	void set_prioridade(int);
	void set_blocos_memoria(int);
	void set_inicio(int);
	void set_codigo_disco(int);
	//Fim da declaracao dos setters

	//Inicio da declaracao dos getters
	int get_tempo_inicializacao();
	int get_tempo_processador();
	bool get_requisicao_impressora();
	bool get_requisicao_scanner();
	bool get_requisicao_modem();
	int get_prioridade();
	int get_blocos_memoria();
	int get_inicio();
	int get_codigo_disco();
	//Fim da declaracao dos getters
	void imprime_infomacoes_processo(int);//sera passado a ele o PID
//Fim da definicao dos metodos do processo
};
#endif
<|endoftext|>


<commit_before>#include "app.h"

#include <memory>
#include <utility>
#include <cmath>

#include "platform.h"
#include "view/view.h"

std::shared_ptr<View> m_view;

void initialize() {
    logMsg("%s\n", "initialize");

    // Create view
    m_view = std::make_shared<View>();

    //
    //

    // Set up openGL state
    glDisable(GL_BLEND);
    glDisable(GL_STENCIL_TEST);
    glEnable(GL_DEPTH_TEST);
    glClearDepthf(1.0);
    glDepthRangef(0.0, 1.0);
    glDepthMask(GL_TRUE);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);

    logMsg("%s\n", "finish initialize");
}

void resize(int _newWidth, int _newHeight) {
    logMsg("%s\n", "resize");

    glViewport(0, 0, _newWidth, _newHeight);

    if (m_view) {
        m_view->setAspect(_newWidth, _newHeight);
    }
}

void update(float _dt) {

}

void render() {
    // Set up openGL for new frame
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::dmat4 view = m_view->getViewMatrix();
    glm::dmat4 viewProj = m_view->getViewProjectionMatrix();

    //
    //

    // TODO: This error checking is incomplete and only marginally useful
    // 1. We need to continue calling glGetError until no error states remain
    // 2. Repeating an error message 60 times per second is not useful, try to consolidate
    GLenum glError = glGetError();
    if (glError) {
        logMsg("GL Error %d!!!\n", glError);
    }
}

void teardown() {
    // TODO: Release resources!
}<commit_msg>openGL include issue<commit_after>#include "app.h"

#include <memory>
#include <utility>
#include <cmath>

#include "platform.h"
#include "view/view.h"

#include "GLES2/gl2.h"
#include "EGL/egl.h"
#include "EGL/eglext.h"

std::shared_ptr<View> m_view;

void initialize() {
    logMsg("%s\n", "initialize");

    // Create view
    m_view = std::make_shared<View>();

    //
    //

    // Set up openGL state
    glDisable(GL_BLEND);
    glDisable(GL_STENCIL_TEST);
    glEnable(GL_DEPTH_TEST);
    glClearDepthf(1.0);
    glDepthRangef(0.0, 1.0);
    glDepthMask(GL_TRUE);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);

    logMsg("%s\n", "finish initialize");
}

void resize(int _newWidth, int _newHeight) {
    logMsg("%s\n", "resize");

    glViewport(0, 0, _newWidth, _newHeight);

    if (m_view) {
        m_view->setAspect(_newWidth, _newHeight);
    }
}

void update(float _dt) {

}

void render() {
    // Set up openGL for new frame
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::dmat4 view = m_view->getViewMatrix();
    glm::dmat4 viewProj = m_view->getViewProjectionMatrix();

    //
    //

    // TODO: This error checking is incomplete and only marginally useful
    // 1. We need to continue calling glGetError until no error states remain
    // 2. Repeating an error message 60 times per second is not useful, try to consolidate
    GLenum glError = glGetError();
    if (glError) {
        logMsg("GL Error %d!!!\n", glError);
    }
}

void teardown() {
    // TODO: Release resources!
}<|endoftext|>


<commit_before>/*!
  \copyright (c) RDO-Team, 2011
  \file      rdo_resource.cpp
  \authors     (rdo@rk9.bmstu.ru)
  \authors     (dluschan@rk9.bmstu.ru)
  \date      16.04.2008
  \brief     RDOResource implementation
  \indent    4T
*/

// ---------------------------------------------------------------------------- PCH
// ----------------------------------------------------------------------- INCLUDES
// ----------------------------------------------------------------------- SYNOPSIS
#include "simulator/runtime/pch.h"
#include "simulator/runtime/rdo_resource.h"
#include "simulator/runtime/rdo_runtime.h"
// --------------------------------------------------------------------------------

OPEN_RDO_RUNTIME_NAMESPACE

// --------------------------------------------------------------------------------
// -------------------- RDOResource
// --------------------------------------------------------------------------------
RDOResource::RDOResource(CREF(LPRDORuntime) pRuntime, CREF(ParamList) paramList, LPIResourceType pResType, ruint resID, ruint typeID, rbool trace, rbool temporary)
	: RDORuntimeObject   (                                      )
	, RDOTraceableObject (trace, resID, rdo::toString(resID + 1))
	, m_state            (RDOResource::CS_None                  )
	, m_type             (typeID                                )
	, m_referenceCount   (0                                     )
	, m_resType          (pResType                              )
	, m_temporary        (temporary                             )
{
	appendParams(paramList.begin(), paramList.end());
	pRuntime->insertNewResource(this);
}

/// @todo     -   ?
RDOResource::RDOResource(CREF(LPRDORuntime) pRuntime, CREF(RDOResource) copy)
	: RDORuntimeObject   (                 )
	, RDOTraceableObject (copy.traceable(), copy.getTraceID(), copy.traceId())
	, m_type             (copy.m_type      )
	, m_state            (copy.m_state     )
	, m_typeId           (copy.m_typeId    )
	, m_paramList        (copy.m_paramList )
	, m_referenceCount   (0                )
	, m_resType          (copy.m_resType   )
	, m_temporary        (copy.m_temporary )
{
	appendParams(copy.m_paramList.begin(), copy.m_paramList.end());
	pRuntime->insertNewResource(this);
/// @todo  history
//	getRuntime()->incrementResourceIdReference( getTraceID() );
}

RDOResource::~RDOResource()
{
	/// @todo ,   breakpoint    this
	//getRuntime()->notify().fireMessage(Notify::RO_BEFOREDELETE, (void*)getTraceID());
	//getRuntime()->onResourceErase(this);
}

rbool RDOResource::operator!= (RDOResource &other)
{
	if (m_type != other.m_type) return true;
	if (m_paramList.size() != other.m_paramList.size()) return true;

	int size = m_paramList.size();
	for (int i = 0; i < size; ++i)
	{
		if (m_paramList.at(i) != other.m_paramList.at(i)) return true;
	}
	return false;
}

LPRDOResource RDOResource::clone(CREF(LPRDORuntime) pRuntime) const
{
	return rdo::Factory<RDOResource>::create(pRuntime, m_paramList, m_resType, getTraceID(), m_type, traceable(), m_temporary);
}

tstring RDOResource::getTypeId()
{
	std::ostringstream str;
	str << m_type;
	return str.str();
}

tstring RDOResource::traceParametersValue()
{
	std::ostringstream str;
	if(m_paramList.size() > 0)
	{
		ParamList::iterator end = m_paramList.end();
		for (ParamList::iterator it = m_paramList.begin();;)
		{
#ifdef RDOSIM_COMPATIBLE
			std::ostringstream _str;
			_str << *it;
			tstring::size_type pos = _str.str().find("e");
			if (pos != tstring::npos)
			{
				tstring __str = _str.str();
				__str.erase(pos + 2, 1);
				str << __str.c_str();
			}
			else
			{
				str << _str.str().c_str();
			}
#else
			str << *it;
#endif
			if (++it == end)
				break;
			str << " ";
		}
	}
	return str.str();
}

tstring RDOResource::traceResourceState(char prefix, CREF(LPRDORuntime) pRuntime)
{
	std::ostringstream res;
	if (traceable() || (prefix != '\0'))
	{
		if (m_state == RDOResource::CS_NoChange || m_state == RDOResource::CS_NonExist)
			return "";

		if (prefix != '\0')
			res << prefix;

		switch (m_state)
		{
		case RDOResource::CS_Create:
			res << "RC ";
			break;
		case RDOResource::CS_Erase:
			res << "RE "
#ifdef RDOSIM_COMPATIBLE
				<< pRuntime->getCurrentTime() << " "
				<< traceTypeId()              << " "
				<< traceId()                  << std::endl;
			return res.str();
#else
				;
#endif
			break;
		default:
			res << "RK ";
			break;
		}

		res << pRuntime->getCurrentTime() << " "
			<< traceTypeId()              << " "
			<< traceId()                  << " "
			<< traceParametersValue()     << std::endl;
	}
	return res.str();
}

CLOSE_RDO_RUNTIME_NAMESPACE
<commit_msg> - удалено лишнее<commit_after>/*!
  \copyright (c) RDO-Team, 2011
  \file      rdo_resource.cpp
  \authors     (rdo@rk9.bmstu.ru)
  \authors     (dluschan@rk9.bmstu.ru)
  \date      16.04.2008
  \brief     RDOResource implementation
  \indent    4T
*/

// ---------------------------------------------------------------------------- PCH
// ----------------------------------------------------------------------- INCLUDES
// ----------------------------------------------------------------------- SYNOPSIS
#include "simulator/runtime/pch.h"
#include "simulator/runtime/rdo_resource.h"
#include "simulator/runtime/rdo_runtime.h"
// --------------------------------------------------------------------------------

OPEN_RDO_RUNTIME_NAMESPACE

// --------------------------------------------------------------------------------
// -------------------- RDOResource
// --------------------------------------------------------------------------------
RDOResource::RDOResource(CREF(LPRDORuntime) pRuntime, CREF(ParamList) paramList, LPIResourceType pResType, ruint resID, ruint typeID, rbool trace, rbool temporary)
	: RDORuntimeObject   (                                      )
	, RDOTraceableObject (trace, resID, rdo::toString(resID + 1))
	, m_state            (RDOResource::CS_None                  )
	, m_type             (typeID                                )
	, m_referenceCount   (0                                     )
	, m_resType          (pResType                              )
	, m_temporary        (temporary                             )
{
	appendParams(paramList.begin(), paramList.end());
	pRuntime->insertNewResource(this);
}

/// @todo     -   ?
RDOResource::RDOResource(CREF(LPRDORuntime) pRuntime, CREF(RDOResource) copy)
	: RDORuntimeObject   (                 )
	, RDOTraceableObject (copy.traceable(), copy.getTraceID(), copy.traceId())
	, m_type             (copy.m_type      )
	, m_state            (copy.m_state     )
	, m_typeId           (copy.m_typeId    )
	, m_paramList        (copy.m_paramList )
	, m_referenceCount   (0                )
	, m_resType          (copy.m_resType   )
	, m_temporary        (copy.m_temporary )
{
	appendParams(copy.m_paramList.begin(), copy.m_paramList.end());
	pRuntime->insertNewResource(this);
/// @todo  history
//	getRuntime()->incrementResourceIdReference( getTraceID() );
}

RDOResource::~RDOResource()
{}

rbool RDOResource::operator!= (RDOResource &other)
{
	if (m_type != other.m_type) return true;
	if (m_paramList.size() != other.m_paramList.size()) return true;

	int size = m_paramList.size();
	for (int i = 0; i < size; ++i)
	{
		if (m_paramList.at(i) != other.m_paramList.at(i)) return true;
	}
	return false;
}

LPRDOResource RDOResource::clone(CREF(LPRDORuntime) pRuntime) const
{
	return rdo::Factory<RDOResource>::create(pRuntime, m_paramList, m_resType, getTraceID(), m_type, traceable(), m_temporary);
}

tstring RDOResource::getTypeId()
{
	std::ostringstream str;
	str << m_type;
	return str.str();
}

tstring RDOResource::traceParametersValue()
{
	std::ostringstream str;
	if(m_paramList.size() > 0)
	{
		ParamList::iterator end = m_paramList.end();
		for (ParamList::iterator it = m_paramList.begin();;)
		{
#ifdef RDOSIM_COMPATIBLE
			std::ostringstream _str;
			_str << *it;
			tstring::size_type pos = _str.str().find("e");
			if (pos != tstring::npos)
			{
				tstring __str = _str.str();
				__str.erase(pos + 2, 1);
				str << __str.c_str();
			}
			else
			{
				str << _str.str().c_str();
			}
#else
			str << *it;
#endif
			if (++it == end)
				break;
			str << " ";
		}
	}
	return str.str();
}

tstring RDOResource::traceResourceState(char prefix, CREF(LPRDORuntime) pRuntime)
{
	std::ostringstream res;
	if (traceable() || (prefix != '\0'))
	{
		if (m_state == RDOResource::CS_NoChange || m_state == RDOResource::CS_NonExist)
			return "";

		if (prefix != '\0')
			res << prefix;

		switch (m_state)
		{
		case RDOResource::CS_Create:
			res << "RC ";
			break;
		case RDOResource::CS_Erase:
			res << "RE "
#ifdef RDOSIM_COMPATIBLE
				<< pRuntime->getCurrentTime() << " "
				<< traceTypeId()              << " "
				<< traceId()                  << std::endl;
			return res.str();
#else
				;
#endif
			break;
		default:
			res << "RK ";
			break;
		}

		res << pRuntime->getCurrentTime() << " "
			<< traceTypeId()              << " "
			<< traceId()                  << " "
			<< traceParametersValue()     << std::endl;
	}
	return res.str();
}

CLOSE_RDO_RUNTIME_NAMESPACE
<|endoftext|>


<commit_before>/*********************************************************************************
 * libskype - C++ library for interacting with a running skype instance.
 * Copyright (C) 2014 Søren Holm <sgh@sgh.dk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 ********************************************************************************/

#include <unistd.h>

#include <iostream>

#include "libskype.h"

using namespace std;

class MyCallbacks : public LibSkypeHandler {

public:
	void message_received(LibSkypeMessage* msg) {
		cout << "New message received" << endl;
		if (msg->editable() && msg->body() == "ping")
			msg->set_body("pong");
	}
};

int main() {
	MyCallbacks callbacks;
	LibSkype skype;
	skype.set_handler(&callbacks);

//	LibSkypeContact* contact =  skype.get_contact("testuser");
//	cout << contact->handle() << endl;
//	contact->transfer_file("uhadada.mp3");
//	contact->send_message("uhadada.mp3");
//	contact->call();
//	usleep(100000);
	while (1)
		usleep(1000000);
}
<commit_msg>Added commandline call and filetransfer.<commit_after>/*********************************************************************************
 * libskype - C++ library for interacting with a running skype instance.
 * Copyright (C) 2014 Søren Holm <sgh@sgh.dk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 ********************************************************************************/
#include "libskype.h"

#include <unistd.h>
#include <stdlib.h>

#include <iostream>

using namespace std;

class MyCallbacks : public LibSkypeHandler {

public:
	void message_received(LibSkypeMessage* msg) {
		cout << "New message received" << endl;
		if (msg->editable() && msg->body() == "ping")
			msg->set_body("pong");
	}
};

void print_usage() {
	cout << "Usage: skypecli <options>               " << endl;
	cout << "  -c <contact>  - Call contact          " << endl;
	cout << "  -f <file>     - Send file to a contact" << endl;
	exit(EXIT_FAILURE);
}

int main(int argc, char* const argv[]) {
	int opt;
	string call_handle;
	string send_file;

	while ((opt = getopt(argc, argv, "c:f:h")) != -1) {
		switch (opt) {
			case 'c':
				call_handle = optarg;
				break;
			case 'f':
				send_file = optarg;
				break;
			default:
				print_usage();
		}
	}

	if (argc < 2)
		print_usage();

	MyCallbacks callbacks;
	LibSkype skype;
	skype.set_handler(&callbacks);

	if (!call_handle.empty()) {
		LibSkypeContact* contact = skype.get_contact(call_handle);
		if (!contact) {
			cout << "Error, no such contact" << endl;
			exit(EXIT_FAILURE);
		}
		cout << "Calling " << contact->handle() << endl;
		contact->call();
	} else
	if (!send_file.empty()) {
		string handle;
		cout << "Send file to: " << flush;
		getline(cin, handle);
		LibSkypeContact* contact = skype.get_contact(handle);
		if (!contact) {
			cout << "Error, no such contact" << endl;
			exit(EXIT_FAILURE);
		}
		cout << "Sending file to " << contact->handle() << endl;
		contact->transfer_file(send_file);

	}

	exit(EXIT_SUCCESS);
}
<|endoftext|>


<commit_before>#ifndef SOFA_COMPONENT_FORCEFIELD_VECTORSPRINGFORCEFIELD_INL
#define SOFA_COMPONENT_FORCEFIELD_VECTORSPRINGFORCEFIELD_INL

#include "VectorSpringForceField.h"
#include <sofa/helper/io/MassSpringLoader.h>
#include <sofa/core/objectmodel/KeypressedEvent.h>
#include <sofa/component/topology/EdgeData.inl>
#include <sofa/component/topology/TopologyChangedEvent.h>
#include <sofa/helper/system/config.h>
#include <assert.h>
#include <iostream>
#include <GL/gl.h>
#include <iostream>
using std::cerr;
using std::endl;

namespace sofa
{

namespace component
{

namespace forcefield
{

template<class DataTypes>
void springCreationFunction(int /*index*/,
        void* param, typename VectorSpringForceField<DataTypes>::Spring& t,
        const topology::Edge& e,
        const std::vector< unsigned int > &ancestors,
        const std::vector< double >& coefs)
{
    VectorSpringForceField<DataTypes> *ff= static_cast<VectorSpringForceField<DataTypes> *>(param);
    if (ff)
    {
        topology::EdgeSetTopology<DataTypes>* topology = dynamic_cast<topology::EdgeSetTopology<DataTypes>*>(ff->getContext()->getMainTopology());
        if (topology)
        {
            //EdgeSetGeometryAlgorithms<DataTypes> *ga=topology->getEdgeSetGeometryAlgorithms();
            //t.restLength=ga->computeRestEdgeLength(index);
            const typename DataTypes::VecCoord& x0 = *ff->getObject1()->getX0();
            t.restVector = x0[e.second] - x0[e.first];
            if (ancestors.size()>0)
            {
                t.kd=t.ks=0;
                const topology::EdgeData<typename VectorSpringForceField<DataTypes>::Spring> &sa=ff->getSpringArray();
                unsigned int i;
                for (i=0; i<ancestors.size(); ++i)
                {
                    t.kd+=(typename DataTypes::Real)(sa[i].kd*coefs[i]);
                    t.ks+=(typename DataTypes::Real)(sa[i].ks*coefs[i]);
                }
            }
            else
            {
                t.kd=ff->getStiffness();
                t.ks=ff->getViscosity();
            }
        }
    }
}

template <class DataTypes>
class VectorSpringForceField<DataTypes>::Loader : public sofa::helper::io::MassSpringLoader
{
public:
    typedef typename DataTypes::Real Real;
    typedef typename DataTypes::Coord Coord;
    VectorSpringForceField<DataTypes>* dest;
    Loader(VectorSpringForceField<DataTypes>* dest) : dest(dest) {}
    virtual void addVectorSpring(int m1, int m2, double ks, double kd, double initpos, double restx, double resty, double restz)
    {
        dest->addSpring(m1,m2,ks,kd,Coord((Real)restx,(Real)resty,(Real)restz));
    }
    virtual void setNumSprings(int /*n*/)
    {
        //dest->resizeArray((unsigned int )n);
    }

};

template <class DataTypes>
bool VectorSpringForceField<DataTypes>::load(const char *filename)
{
    if (filename && filename[0])
    {
        Loader loader(this);
        return loader.load(filename);
    }
    else return false;
}

template <class DataTypes>
void VectorSpringForceField<DataTypes>::resizeArray(unsigned int n)
{
    springArray.resize(n);
}

template <class DataTypes>
void VectorSpringForceField<DataTypes>::addSpring(int m1, int m2, double ks, double kd, Coord restVector)
{
    if (useTopology && topology)
    {
        topology::EdgeSetTopologyContainer *container=topology->getEdgeSetTopologyContainer();

        int e=container->getEdgeIndex((unsigned int)m1,(unsigned int)m2);
        if (e>=0)
            springArray[e]=Spring((Real)ks,(Real)kd,restVector);
    }
    else
    {
        springArray.push_back(Spring((Real)ks, (Real)kd, restVector));
        edgeArray.push_back(topology::Edge(m1,m2));
    }
}

template <class DataTypes>
VectorSpringForceField<DataTypes>::VectorSpringForceField(MechanicalState* _object)
    : object1(_object), object2(_object)
    , m_potentialEnergy( 0.0 ), useTopology( false ), topology ( NULL )
    , m_filename( dataField(&m_filename,std::string(""),"filename","File name from which the spring informations are loaded") )
    , m_stiffness( dataField(&m_stiffness,1.0,"stiffness","Default edge stiffness used in absence of file information") )
    , m_viscosity( dataField(&m_viscosity,1.0,"viscosity","Default edge viscosity used in absence of file information") )
{
    springArray.setCreateFunction(springCreationFunction<DataTypes>);
    springArray.setCreateParameter( (void *) this );
}

template <class DataTypes>
VectorSpringForceField<DataTypes>::VectorSpringForceField(MechanicalState* _object1, MechanicalState* _object2)
    : object1(_object1), object2(_object2)
    , m_potentialEnergy( 0.0 ), useTopology( false ), topology ( NULL )
    , m_filename( dataField(&m_filename,std::string(""),"filename","File name from which the spring informations are loaded") )
    , m_stiffness( dataField(&m_stiffness,1.0,"stiffness","Default edge stiffness used in absence of file information") )
    , m_viscosity( dataField(&m_viscosity,1.0,"viscosity","Default edge viscosity used in absence of file information") )
{
    springArray.setCreateFunction(springCreationFunction<DataTypes>);
    springArray.setCreateParameter( (void *) this );
}

template <class DataTypes>
void VectorSpringForceField<DataTypes>::init()
{
    this->InteractionForceField::init();
    if( object1==NULL )
    {
        sofa::core::objectmodel::BaseObject* mstate = getContext()->getMechanicalState();
        assert(mstate!=NULL);
        MechanicalState* state = dynamic_cast<MechanicalState*>(mstate );
        assert( state!= NULL );
        object1 = object2 = state;
        topology = dynamic_cast<topology::EdgeSetTopology<DataTypes>*>(getContext()->getMainTopology());
    }

    if (!m_filename.getValue().empty())
    {
        // load the springs from a file
        load(( const char *)(m_filename.getValue().c_str()));
    }
    else if (topology)
    {
        // create springs based on the mesh topology
        useTopology = true;
        createDefaultSprings();
        f_listening.setValue(true);
    }
}

template <class DataTypes>
void VectorSpringForceField<DataTypes>::createDefaultSprings()
{
    topology::EdgeSetTopologyContainer *container=topology->getEdgeSetTopologyContainer();
    const std::vector<topology::Edge> &ea=container->getEdgeArray();
    std::cout << "Creating "<<ea.size()<<" Vector Springs from EdgeSetTopology"<<std::endl;
    springArray.resize(ea.size());
    //EdgeSetGeometryAlgorithms<DataTypes> *ga=topology->getEdgeSetGeometryAlgorithms();
    //EdgeLengthArrayInterface<Real,DataTypes> elai(springArray);
    //ga->computeEdgeLength(elai);
    const VecCoord& x0 = *this->object1->getX0();
    unsigned int i;
    for (i=0; i<ea.size(); ++i)
    {
        springArray[i].ks=(Real)m_stiffness.getValue();
        springArray[i].kd=(Real)m_viscosity.getValue();
        springArray[i].restVector = x0[ea[i].second]-x0[ea[i].first];
    }

}
template<class DataTypes>
void VectorSpringForceField<DataTypes>::handleEvent( Event* e )
{
    if (useTopology)
    {
        if( sofa::core::objectmodel::KeypressedEvent* ke = dynamic_cast<sofa::core::objectmodel::KeypressedEvent*>( e ) )
        {
            /// handle ctrl+d key
            if (ke->getKey()=='D')
            {
                if (topology->getEdgeSetTopologyContainer()->getNumberOfEdges()>12)
                {
                    topology::EdgeSetTopologyAlgorithms<DataTypes> *esta=topology->getEdgeSetTopologyAlgorithms();
                    std::vector<unsigned int> edgeArray;
                    edgeArray.push_back(12);
                    esta->removeEdges(edgeArray);
                }
                //            esta->splitEdges(edgeArray);
            }
        }
        else
        {
            sofa::component::topology::TopologyChangedEvent *tce=dynamic_cast<sofa::component::topology::TopologyChangedEvent *>(e);
            /// test that the event is a change of topology and that it
            if ((tce) && (tce->getTopology()== topology))
            {
                std::list<const sofa::core::componentmodel::topology::TopologyChange *>::const_iterator itBegin=topology->firstChange();
                std::list<const sofa::core::componentmodel::topology::TopologyChange *>::const_iterator itEnd=topology->lastChange();
                /// Topological events are handled by the EdgeData structure
                springArray.handleTopologyEvents(itBegin,itEnd);
            }
        }
    }
}

template<class DataTypes>
//void VectorSpringForceField<DataTypes>::addForce(VecDeriv& f, const VecCoord& p, const VecDeriv& v)
void VectorSpringForceField<DataTypes>::addForce()
{
    //assert(this->mstate);
    m_potentialEnergy = 0;
    const std::vector<topology::Edge> &ea=(useTopology)?topology->getEdgeSetTopologyContainer()->getEdgeArray() : edgeArray;
    Coord u;

    VecDeriv& f1 = *object1->getF();
    const VecCoord& p1 = *object1->getX();
    const VecDeriv& v1 = *object1->getV();

    VecDeriv& f2 = *object2->getF();
    const VecCoord& p2 = *object2->getX();
    const VecDeriv& v2 = *object2->getV();

    f1.resize(p1.size());
    f2.resize(p2.size());

    Deriv relativeVelocity,force;
    for (unsigned int i=0; i<ea.size(); i++)
    {
        const topology::Edge &e=ea[i];
        const Spring &s=springArray[i];
        // paul---------------------------------------------------------------
        Deriv current_direction = p2[e.second]-p1[e.first];
        Deriv squash_vector = current_direction - s.restVector;
        Deriv relativeVelocity = v2[e.second]-v1[e.first];
        force = (squash_vector * s.ks) + (relativeVelocity * s.kd);

        f1[e.first]+=force;
        f2[e.second]-=force;
    }
}

template<class DataTypes>
//void VectorSpringForceField<DataTypes>::addDForce(VecDeriv& df, const VecDeriv& dx)
void VectorSpringForceField<DataTypes>::addDForce()
{
    const std::vector<topology::Edge> &ea=(useTopology)?topology->getEdgeSetTopologyContainer()->getEdgeArray() : edgeArray;
    Deriv dforce,d;
    unsigned int i;

    VecDeriv& df1 = *object1->getF();
    const VecCoord& dx1 = *object1->getDx();

    VecDeriv& df2 = *object2->getF();
    const VecCoord& dx2 = *object2->getDx();

    df1.resize(dx1.size());
    df2.resize(dx2.size());

    for ( i=0; i<ea.size(); i++)
    {
        const topology::Edge &e=ea[i];
        const Spring &s=springArray[i];
        d = dx2[e.second]-dx1[e.first];
        dforce = d*s.ks;
        df2[e.first]+=dforce;
        df1[e.second]-=dforce;
    }

}

template<class DataTypes>
void VectorSpringForceField<DataTypes>::draw()
{
    if (getContext()->getShowForceFields()==false)
        return;
    //const VecCoord& p = *this->mstate->getX();
    const VecCoord& p1 = *this->object1->getX();
    const VecCoord& p2 = *this->object2->getX();
    const std::vector<topology::Edge> &ea=(useTopology)?topology->getEdgeSetTopologyContainer()->getEdgeArray() : edgeArray;

    glDisable(GL_LIGHTING);

    glBegin(GL_LINES);
    for (unsigned int i=0; i<springArray.size(); i++)
    {
        const topology::Edge &e=ea[i];
        //const Spring &s=springArray[i];

        glColor4f(0,1,1,0.5f);

        glVertex3d(p1[e.first][0],p1[e.first][1],p1[e.first][2]);
        glVertex3d(p2[e.second][0],p2[e.second][1],p2[e.second][2]);
    }
    glEnd();
}

} // namespace forcefield

} // namespace component

} // namespace sofa

#endif
<commit_msg>r1237/sofa-dev : BUGFIX: inversed addDForce in VectorSpringForceField, and crash when picking spheres.<commit_after>#ifndef SOFA_COMPONENT_FORCEFIELD_VECTORSPRINGFORCEFIELD_INL
#define SOFA_COMPONENT_FORCEFIELD_VECTORSPRINGFORCEFIELD_INL

#include "VectorSpringForceField.h"
#include <sofa/helper/io/MassSpringLoader.h>
#include <sofa/core/objectmodel/KeypressedEvent.h>
#include <sofa/component/topology/EdgeData.inl>
#include <sofa/component/topology/TopologyChangedEvent.h>
#include <sofa/helper/system/config.h>
#include <assert.h>
#include <iostream>
#include <GL/gl.h>
#include <iostream>
using std::cerr;
using std::endl;

namespace sofa
{

namespace component
{

namespace forcefield
{

template<class DataTypes>
void springCreationFunction(int /*index*/,
        void* param, typename VectorSpringForceField<DataTypes>::Spring& t,
        const topology::Edge& e,
        const std::vector< unsigned int > &ancestors,
        const std::vector< double >& coefs)
{
    VectorSpringForceField<DataTypes> *ff= static_cast<VectorSpringForceField<DataTypes> *>(param);
    if (ff)
    {
        topology::EdgeSetTopology<DataTypes>* topology = dynamic_cast<topology::EdgeSetTopology<DataTypes>*>(ff->getContext()->getMainTopology());
        if (topology)
        {
            //EdgeSetGeometryAlgorithms<DataTypes> *ga=topology->getEdgeSetGeometryAlgorithms();
            //t.restLength=ga->computeRestEdgeLength(index);
            const typename DataTypes::VecCoord& x0 = *ff->getObject1()->getX0();
            t.restVector = x0[e.second] - x0[e.first];
            if (ancestors.size()>0)
            {
                t.kd=t.ks=0;
                const topology::EdgeData<typename VectorSpringForceField<DataTypes>::Spring> &sa=ff->getSpringArray();
                unsigned int i;
                for (i=0; i<ancestors.size(); ++i)
                {
                    t.kd+=(typename DataTypes::Real)(sa[i].kd*coefs[i]);
                    t.ks+=(typename DataTypes::Real)(sa[i].ks*coefs[i]);
                }
            }
            else
            {
                t.kd=ff->getStiffness();
                t.ks=ff->getViscosity();
            }
        }
    }
}

template <class DataTypes>
class VectorSpringForceField<DataTypes>::Loader : public sofa::helper::io::MassSpringLoader
{
public:
    typedef typename DataTypes::Real Real;
    typedef typename DataTypes::Coord Coord;
    VectorSpringForceField<DataTypes>* dest;
    Loader(VectorSpringForceField<DataTypes>* dest) : dest(dest) {}
    virtual void addVectorSpring(int m1, int m2, double ks, double kd, double initpos, double restx, double resty, double restz)
    {
        dest->addSpring(m1,m2,ks,kd,Coord((Real)restx,(Real)resty,(Real)restz));
    }
    virtual void setNumSprings(int /*n*/)
    {
        //dest->resizeArray((unsigned int )n);
    }

};

template <class DataTypes>
bool VectorSpringForceField<DataTypes>::load(const char *filename)
{
    if (filename && filename[0])
    {
        Loader loader(this);
        return loader.load(filename);
    }
    else return false;
}

template <class DataTypes>
void VectorSpringForceField<DataTypes>::resizeArray(unsigned int n)
{
    springArray.resize(n);
}

template <class DataTypes>
void VectorSpringForceField<DataTypes>::addSpring(int m1, int m2, double ks, double kd, Coord restVector)
{
    if (useTopology && topology)
    {
        topology::EdgeSetTopologyContainer *container=topology->getEdgeSetTopologyContainer();

        int e=container->getEdgeIndex((unsigned int)m1,(unsigned int)m2);
        if (e>=0)
            springArray[e]=Spring((Real)ks,(Real)kd,restVector);
    }
    else
    {
        springArray.push_back(Spring((Real)ks, (Real)kd, restVector));
        edgeArray.push_back(topology::Edge(m1,m2));
    }
}

template <class DataTypes>
VectorSpringForceField<DataTypes>::VectorSpringForceField(MechanicalState* _object)
    : object1(_object), object2(_object)
    , m_potentialEnergy( 0.0 ), useTopology( false ), topology ( NULL )
    , m_filename( dataField(&m_filename,std::string(""),"filename","File name from which the spring informations are loaded") )
    , m_stiffness( dataField(&m_stiffness,1.0,"stiffness","Default edge stiffness used in absence of file information") )
    , m_viscosity( dataField(&m_viscosity,1.0,"viscosity","Default edge viscosity used in absence of file information") )
{
    springArray.setCreateFunction(springCreationFunction<DataTypes>);
    springArray.setCreateParameter( (void *) this );
}

template <class DataTypes>
VectorSpringForceField<DataTypes>::VectorSpringForceField(MechanicalState* _object1, MechanicalState* _object2)
    : object1(_object1), object2(_object2)
    , m_potentialEnergy( 0.0 ), useTopology( false ), topology ( NULL )
    , m_filename( dataField(&m_filename,std::string(""),"filename","File name from which the spring informations are loaded") )
    , m_stiffness( dataField(&m_stiffness,1.0,"stiffness","Default edge stiffness used in absence of file information") )
    , m_viscosity( dataField(&m_viscosity,1.0,"viscosity","Default edge viscosity used in absence of file information") )
{
    springArray.setCreateFunction(springCreationFunction<DataTypes>);
    springArray.setCreateParameter( (void *) this );
}

template <class DataTypes>
void VectorSpringForceField<DataTypes>::init()
{
    this->InteractionForceField::init();
    if( object1==NULL )
    {
        sofa::core::objectmodel::BaseObject* mstate = getContext()->getMechanicalState();
        assert(mstate!=NULL);
        MechanicalState* state = dynamic_cast<MechanicalState*>(mstate );
        assert( state!= NULL );
        object1 = object2 = state;
        topology = dynamic_cast<topology::EdgeSetTopology<DataTypes>*>(getContext()->getMainTopology());
    }

    if (!m_filename.getValue().empty())
    {
        // load the springs from a file
        load(( const char *)(m_filename.getValue().c_str()));
    }
    else if (topology)
    {
        // create springs based on the mesh topology
        useTopology = true;
        createDefaultSprings();
        f_listening.setValue(true);
    }
}

template <class DataTypes>
void VectorSpringForceField<DataTypes>::createDefaultSprings()
{
    topology::EdgeSetTopologyContainer *container=topology->getEdgeSetTopologyContainer();
    const std::vector<topology::Edge> &ea=container->getEdgeArray();
    std::cout << "Creating "<<ea.size()<<" Vector Springs from EdgeSetTopology"<<std::endl;
    springArray.resize(ea.size());
    //EdgeSetGeometryAlgorithms<DataTypes> *ga=topology->getEdgeSetGeometryAlgorithms();
    //EdgeLengthArrayInterface<Real,DataTypes> elai(springArray);
    //ga->computeEdgeLength(elai);
    const VecCoord& x0 = *this->object1->getX0();
    unsigned int i;
    for (i=0; i<ea.size(); ++i)
    {
        springArray[i].ks=(Real)m_stiffness.getValue();
        springArray[i].kd=(Real)m_viscosity.getValue();
        springArray[i].restVector = x0[ea[i].second]-x0[ea[i].first];
    }

}
template<class DataTypes>
void VectorSpringForceField<DataTypes>::handleEvent( Event* e )
{
    if (useTopology)
    {
        if( sofa::core::objectmodel::KeypressedEvent* ke = dynamic_cast<sofa::core::objectmodel::KeypressedEvent*>( e ) )
        {
            /// handle ctrl+d key
            if (ke->getKey()=='D')
            {
                if (topology->getEdgeSetTopologyContainer()->getNumberOfEdges()>12)
                {
                    topology::EdgeSetTopologyAlgorithms<DataTypes> *esta=topology->getEdgeSetTopologyAlgorithms();
                    std::vector<unsigned int> edgeArray;
                    edgeArray.push_back(12);
                    esta->removeEdges(edgeArray);
                }
                //            esta->splitEdges(edgeArray);
            }
        }
        else
        {
            sofa::component::topology::TopologyChangedEvent *tce=dynamic_cast<sofa::component::topology::TopologyChangedEvent *>(e);
            /// test that the event is a change of topology and that it
            if ((tce) && (tce->getTopology()== topology))
            {
                std::list<const sofa::core::componentmodel::topology::TopologyChange *>::const_iterator itBegin=topology->firstChange();
                std::list<const sofa::core::componentmodel::topology::TopologyChange *>::const_iterator itEnd=topology->lastChange();
                /// Topological events are handled by the EdgeData structure
                springArray.handleTopologyEvents(itBegin,itEnd);
            }
        }
    }
}

template<class DataTypes>
//void VectorSpringForceField<DataTypes>::addForce(VecDeriv& f, const VecCoord& p, const VecDeriv& v)
void VectorSpringForceField<DataTypes>::addForce()
{
    //assert(this->mstate);
    m_potentialEnergy = 0;
    const std::vector<topology::Edge> &ea=(useTopology)?topology->getEdgeSetTopologyContainer()->getEdgeArray() : edgeArray;
    Coord u;

    VecDeriv& f1 = *object1->getF();
    const VecCoord& p1 = *object1->getX();
    const VecDeriv& v1 = *object1->getV();

    VecDeriv& f2 = *object2->getF();
    const VecCoord& p2 = *object2->getX();
    const VecDeriv& v2 = *object2->getV();

    f1.resize(p1.size());
    f2.resize(p2.size());

    Deriv relativeVelocity,force;
    for (unsigned int i=0; i<ea.size(); i++)
    {
        const topology::Edge &e=ea[i];
        const Spring &s=springArray[i];
        // paul---------------------------------------------------------------
        Deriv current_direction = p2[e.second]-p1[e.first];
        Deriv squash_vector = current_direction - s.restVector;
        Deriv relativeVelocity = v2[e.second]-v1[e.first];
        force = (squash_vector * s.ks) + (relativeVelocity * s.kd);

        f1[e.first]+=force;
        f2[e.second]-=force;
    }
}

template<class DataTypes>
//void VectorSpringForceField<DataTypes>::addDForce(VecDeriv& df, const VecDeriv& dx)
void VectorSpringForceField<DataTypes>::addDForce()
{
    const std::vector<topology::Edge> &ea=(useTopology)?topology->getEdgeSetTopologyContainer()->getEdgeArray() : edgeArray;
    Deriv dforce,d;
    unsigned int i;

    VecDeriv& df1 = *object1->getF();
    const VecCoord& dx1 = *object1->getDx();

    VecDeriv& df2 = *object2->getF();
    const VecCoord& dx2 = *object2->getDx();

    df1.resize(dx1.size());
    df2.resize(dx2.size());

    for ( i=0; i<ea.size(); i++)
    {
        const topology::Edge &e=ea[i];
        const Spring &s=springArray[i];
        d = dx2[e.second]-dx1[e.first];
        dforce = d*s.ks;
        df1[e.first]+=dforce;
        df2[e.second]-=dforce;
    }

}

template<class DataTypes>
void VectorSpringForceField<DataTypes>::draw()
{
    if (!((this->object1 == this->object2)?getContext()->getShowForceFields():getContext()->getShowInteractionForceFields()))
        return;
    //const VecCoord& p = *this->mstate->getX();
    const VecCoord& p1 = *this->object1->getX();
    const VecCoord& p2 = *this->object2->getX();
    const std::vector<topology::Edge> &ea=(useTopology)?topology->getEdgeSetTopologyContainer()->getEdgeArray() : edgeArray;

    glDisable(GL_LIGHTING);

    glBegin(GL_LINES);
    for (unsigned int i=0; i<springArray.size(); i++)
    {
        const topology::Edge &e=ea[i];
        //const Spring &s=springArray[i];

        glColor4f(0,1,1,0.5f);

        glVertex3d(p1[e.first][0],p1[e.first][1],p1[e.first][2]);
        glVertex3d(p2[e.second][0],p2[e.second][1],p2[e.second][2]);
    }
    glEnd();
}

} // namespace forcefield

} // namespace component

} // namespace sofa

#endif
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit https://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2016-2018 Esteban Tovagliari, The appleseedhq Organization
//
// 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.
//

// appleseed.foundation headers.
#include "foundation/utility/api/apistring.h"
#include "foundation/utility/searchpaths.h"
#include "foundation/utility/test.h"

// Standard headers.
#include <cassert>
#include <cstdlib>
#include <string>

using namespace foundation;
using namespace std;

TEST_SUITE(Foundation_Utility_SearchPaths)
{
    static const char* TestEnvVarName = "APPLESEED_TEST_SEARCHPATH";

#ifdef _WIN32

    void set_environment_var(const char* name, const char* value)
    {
#ifndef NDEBUG
        const errno_t result =
#endif
            _putenv_s(name, value);
        assert(result == 0);
    }

    TEST_CASE(Constructor_EmptyEnvironmentVariable)
    {
        set_environment_var(TestEnvVarName, "");

        const SearchPaths searchpaths(TestEnvVarName, ';');

        const APIString result = searchpaths.to_string(';');
        EXPECT_EQ("", to_string(result));
    }

    TEST_CASE(Constructor_NonEmptyEnvironmentVariable)
    {
        set_environment_var(TestEnvVarName, "C:\\Windows\\System32;C:\\Windows;C:\\Program Files");

        const SearchPaths searchpaths(TestEnvVarName, ';');

        const APIString result = searchpaths.to_string(';');
        EXPECT_EQ("C:\\Windows\\System32;C:\\Windows;C:\\Program Files", to_string(result));
    }

    TEST_CASE(ClearExplicitPaths)
    {
        set_environment_var(TestEnvVarName, "C:\\Windows\\System32;C:\\Windows;C:\\Program Files");

        SearchPaths searchpaths(TestEnvVarName, ';');
        searchpaths.set_root_path("C:\\Some\\Root\\Path");
        searchpaths.push_back_explicit_path("C:\\Users\\UserName\\appleseed");

        searchpaths.clear_explicit_paths();

        const APIString result = searchpaths.to_string(';');
        EXPECT_EQ("C:\\Some\\Root\\Path;C:\\Windows\\System32;C:\\Windows;C:\\Program Files", to_string(result));
    }

    TEST_CASE(ToString)
    {
        SearchPaths searchpaths;
        searchpaths.push_back_explicit_path("C:\\Windows\\System32");
        searchpaths.push_back_explicit_path("C:\\Windows");
        searchpaths.push_back_explicit_path("C:\\Program Files");

        const APIString result = searchpaths.to_string(';');

        EXPECT_EQ("C:\\Windows\\System32;C:\\Windows;C:\\Program Files", to_string(result));
    }

    TEST_CASE(ToStringReversed)
    {
        SearchPaths searchpaths;
        searchpaths.push_back_explicit_path("C:\\Windows\\System32");
        searchpaths.push_back_explicit_path("C:\\Windows");
        searchpaths.push_back_explicit_path("C:\\Program Files");

        const APIString result = searchpaths.to_string_reversed(';');

        EXPECT_EQ("C:\\Program Files;C:\\Windows;C:\\Windows\\System32", to_string(result));
    }

#else

    void set_environment_var(const char* name, const char* value)
    {
#ifndef NDEBUG
        const int result =
#endif
            setenv(name, value, 1);
        assert(result == 0);
    }

    TEST_CASE(Constructor_EmptyEnvironmentVariable)
    {
        set_environment_var(TestEnvVarName, "");

        const SearchPaths searchpaths(TestEnvVarName, ':');

        const APIString result = searchpaths.to_string(':');
        EXPECT_EQ("", to_string(result));
    }

    TEST_CASE(Constructor_NonEmptyEnvironmentVariable)
    {
        set_environment_var(TestEnvVarName, "/tmp:/usr/tmp:/var/local/tmp");

        const SearchPaths searchpaths(TestEnvVarName, ':');

        const APIString result = searchpaths.to_string(':');
        EXPECT_EQ("/tmp:/usr/tmp:/var/local/tmp", to_string(result));
    }

    TEST_CASE(ClearExplicitPaths)
    {
        set_environment_var(TestEnvVarName, "/tmp:/usr/tmp:/var/local/tmp");

        SearchPaths searchpaths(TestEnvVarName, ':');
        searchpaths.set_root_path("/some/root/path");
        searchpaths.push_back_explicit_path("/home/username/appleseed");

        searchpaths.clear_explicit_paths();

        const APIString result = searchpaths.to_string(':');
        EXPECT_EQ("/some/root/path:/tmp:/usr/tmp:/var/local/tmp", to_string(result));
    }

    TEST_CASE(ToString)
    {
        SearchPaths searchpaths;
        searchpaths.push_back_explicit_path("/tmp");
        searchpaths.push_back_explicit_path("/usr/tmp");
        searchpaths.push_back_explicit_path("/var/local/tmp");

        const APIString result = searchpaths.to_string(':');

        EXPECT_EQ("/tmp:/usr/tmp:/var/local/tmp", to_string(result));
    }

    TEST_CASE(ToStringReversed)
    {
        SearchPaths searchpaths;
        searchpaths.push_back_explicit_path("/tmp");
        searchpaths.push_back_explicit_path("/usr/tmp");
        searchpaths.push_back_explicit_path("/var/local/tmp");

        const APIString result = searchpaths.to_string_reversed(':');

        EXPECT_EQ("/var/local/tmp:/usr/tmp:/tmp", to_string(result));
    }

#endif
}
<commit_msg>Rename variables to improve naming consistency<commit_after>
//
// This source file is part of appleseed.
// Visit https://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2016-2018 Esteban Tovagliari, The appleseedhq Organization
//
// 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.
//

// appleseed.foundation headers.
#include "foundation/utility/api/apistring.h"
#include "foundation/utility/searchpaths.h"
#include "foundation/utility/test.h"

// Standard headers.
#include <cassert>
#include <cstdlib>
#include <string>

using namespace foundation;
using namespace std;

TEST_SUITE(Foundation_Utility_SearchPaths)
{
    static const char* TestEnvVarName = "APPLESEED_TEST_SEARCHPATH";

#ifdef _WIN32

    void set_environment_var(const char* name, const char* value)
    {
#ifndef NDEBUG
        const errno_t result =
#endif
            _putenv_s(name, value);
        assert(result == 0);
    }

    TEST_CASE(Constructor_EmptyEnvironmentVariable)
    {
        set_environment_var(TestEnvVarName, "");

        const SearchPaths search_paths(TestEnvVarName, ';');

        const APIString result = search_paths.to_string(';');
        EXPECT_EQ("", to_string(result));
    }

    TEST_CASE(Constructor_NonEmptyEnvironmentVariable)
    {
        set_environment_var(TestEnvVarName, "C:\\Windows\\System32;C:\\Windows;C:\\Program Files");

        const SearchPaths search_paths(TestEnvVarName, ';');

        const APIString result = search_paths.to_string(';');
        EXPECT_EQ("C:\\Windows\\System32;C:\\Windows;C:\\Program Files", to_string(result));
    }

    TEST_CASE(ClearExplicitPaths)
    {
        set_environment_var(TestEnvVarName, "C:\\Windows\\System32;C:\\Windows;C:\\Program Files");

        SearchPaths search_paths(TestEnvVarName, ';');
        search_paths.set_root_path("C:\\Some\\Root\\Path");
        search_paths.push_back_explicit_path("C:\\Users\\UserName\\appleseed");

        search_paths.clear_explicit_paths();

        const APIString result = search_paths.to_string(';');
        EXPECT_EQ("C:\\Some\\Root\\Path;C:\\Windows\\System32;C:\\Windows;C:\\Program Files", to_string(result));
    }

    TEST_CASE(ToString)
    {
        SearchPaths search_paths;
        search_paths.push_back_explicit_path("C:\\Windows\\System32");
        search_paths.push_back_explicit_path("C:\\Windows");
        search_paths.push_back_explicit_path("C:\\Program Files");

        const APIString result = search_paths.to_string(';');

        EXPECT_EQ("C:\\Windows\\System32;C:\\Windows;C:\\Program Files", to_string(result));
    }

    TEST_CASE(ToStringReversed)
    {
        SearchPaths search_paths;
        search_paths.push_back_explicit_path("C:\\Windows\\System32");
        search_paths.push_back_explicit_path("C:\\Windows");
        search_paths.push_back_explicit_path("C:\\Program Files");

        const APIString result = search_paths.to_string_reversed(';');

        EXPECT_EQ("C:\\Program Files;C:\\Windows;C:\\Windows\\System32", to_string(result));
    }

#else

    void set_environment_var(const char* name, const char* value)
    {
#ifndef NDEBUG
        const int result =
#endif
            setenv(name, value, 1);
        assert(result == 0);
    }

    TEST_CASE(Constructor_EmptyEnvironmentVariable)
    {
        set_environment_var(TestEnvVarName, "");

        const SearchPaths search_paths(TestEnvVarName, ':');

        const APIString result = search_paths.to_string(':');
        EXPECT_EQ("", to_string(result));
    }

    TEST_CASE(Constructor_NonEmptyEnvironmentVariable)
    {
        set_environment_var(TestEnvVarName, "/tmp:/usr/tmp:/var/local/tmp");

        const SearchPaths search_paths(TestEnvVarName, ':');

        const APIString result = search_paths.to_string(':');
        EXPECT_EQ("/tmp:/usr/tmp:/var/local/tmp", to_string(result));
    }

    TEST_CASE(ClearExplicitPaths)
    {
        set_environment_var(TestEnvVarName, "/tmp:/usr/tmp:/var/local/tmp");

        SearchPaths search_paths(TestEnvVarName, ':');
        search_paths.set_root_path("/some/root/path");
        search_paths.push_back_explicit_path("/home/username/appleseed");

        search_paths.clear_explicit_paths();

        const APIString result = search_paths.to_string(':');
        EXPECT_EQ("/some/root/path:/tmp:/usr/tmp:/var/local/tmp", to_string(result));
    }

    TEST_CASE(ToString)
    {
        SearchPaths search_paths;
        search_paths.push_back_explicit_path("/tmp");
        search_paths.push_back_explicit_path("/usr/tmp");
        search_paths.push_back_explicit_path("/var/local/tmp");

        const APIString result = search_paths.to_string(':');

        EXPECT_EQ("/tmp:/usr/tmp:/var/local/tmp", to_string(result));
    }

    TEST_CASE(ToStringReversed)
    {
        SearchPaths search_paths;
        search_paths.push_back_explicit_path("/tmp");
        search_paths.push_back_explicit_path("/usr/tmp");
        search_paths.push_back_explicit_path("/var/local/tmp");

        const APIString result = search_paths.to_string_reversed(':');

        EXPECT_EQ("/var/local/tmp:/usr/tmp:/tmp", to_string(result));
    }

#endif
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2021 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/webbrowser/interaction/cefinteractionhandler.h>
#include <modules/webbrowser/interaction/cefkeyboardmapping.h>
#include <modules/webbrowser/renderhandlergl.h>
#include <inviwo/core/interaction/events/pickingevent.h>
#include <inviwo/core/interaction/events/resizeevent.h>
#include <inviwo/core/interaction/events/wheelevent.h>
#include <inviwo/core/interaction/events/touchevent.h>

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

namespace inviwo {

CEFInteractionHandler::CEFInteractionHandler(CefRefPtr<CefBrowserHost> host) : host_(host){};

void CEFInteractionHandler::invokeEvent(Event* event) {
    switch (event->hash()) {
        case ResizeEvent::chash(): {
            if (renderHandler_) {
                auto resizeEvent = static_cast<ResizeEvent*>(event);
                renderHandler_->updateCanvasSize(host_->GetBrowser(), resizeEvent->size());
                host_->WasResized();
            }
            break;
        }
        case KeyboardEvent::chash(): {
            auto keyEvent = event->getAs<KeyboardEvent>();
            auto cefEvent = mapKeyEvent(keyEvent);
            host_->SendKeyEvent(cefEvent);
            // Send CHAR event for characters, but not non-char keys like arrows,
            // function keys or clear.
            auto isCharacter = std::iscntrl(cefEvent.character) == 0;
            if (isCharacter && (keyEvent->state() & KeyState::Press)) {
                cefEvent.type = KEYEVENT_CHAR;
                // Fixes 'Legacy' key codes for keypress events at
                // https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html
                cefEvent.windows_key_code = cefEvent.character;
                host_->SendKeyEvent(cefEvent);
            }
            event->markAsUsed();
            break;
        }
    }
}

void CEFInteractionHandler::handlePickingEvent(PickingEvent* p) {
    if (p->getEvent()->hash() == MouseEvent::chash()) {
        auto mouseEvent = p->getEventAs<MouseEvent>();
        updateMouseStates(mouseEvent);
        auto cefMouseEvent = mapMouseEvent(mouseEvent);
        if (mouseEvent->state() & MouseState::Move) {
            bool mouseLeave = false;
            host_->SendMouseMoveEvent(cefMouseEvent, mouseLeave);
            p->markAsUsed();
        } else if (mouseEvent->state() & MouseState::Press ||
                   mouseEvent->state() & MouseState::Release) {
            CefBrowserHost::MouseButtonType type;

            if (mouseEvent->button() & MouseButton::Left) {
                type = MBT_LEFT;
            } else if (mouseEvent->button() & MouseButton::Middle) {
                type = MBT_MIDDLE;
            } else {  // if (mouseEvent->button() & MouseButton::Right) {
                type = MBT_RIGHT;
            }
            bool mouseUp = MouseState::Release & mouseEvent->state() ? true : false;
            int clickCount = MouseState::DoubleClick & mouseEvent->state() ? 2 : 1;
            host_->SendMouseClickEvent(cefMouseEvent, type, mouseUp, clickCount);
            p->markAsUsed();
        }
    } else if (auto touchEvent = p->getEventAs<TouchEvent>()) {

        if (!touchEvent->hasTouchPoints()) {
            return;
        }
        TouchDevice::DeviceType type = touchEvent->getDevice()
                                           ? touchEvent->getDevice()->getType()
                                           : TouchDevice::DeviceType::TouchScreen;
        if (type == TouchDevice::DeviceType::TouchPad) {
            // Mouse events are emulated on touch pads for single touch point
            // but we need still need to consume multi-touch events if user pressed on
            p->markAsUsed();
            return;
        }
        const auto& touchPoints = touchEvent->touchPoints();
        for (auto touchPoint : touchPoints) {
            auto cefEvent = mapTouchEvent(&touchPoint, touchEvent->getDevice());
            host_->SendTouchEvent(cefEvent);
        }
        p->markAsUsed();

    } else if (auto wheelEvent = p->getEventAs<WheelEvent>()) {
        auto cefMouseEvent = mapMouseEvent(wheelEvent);
        host_->SendMouseWheelEvent(cefMouseEvent, static_cast<int>(wheelEvent->delta().x),
                                   static_cast<int>(wheelEvent->delta().y));
        p->markAsUsed();
    }
}

CefMouseEvent CEFInteractionHandler::mapMouseEvent(const MouseInteractionEvent* e) {
    CefMouseEvent cefEvent;
    cefEvent.x = static_cast<int>(e->x());
    cefEvent.y = static_cast<int>(e->canvasSize().y) - static_cast<int>(e->y());
    cefEvent.modifiers = modifiers_;
    return cefEvent;
}

CefTouchEvent CEFInteractionHandler::mapTouchEvent(const TouchPoint* p, const TouchDevice* device) {
    CefTouchEvent cefEvent;
    cefEvent.id = p->id();
    // X coordinate relative to the left side of the view.
    cefEvent.x = static_cast<float>(p->pos().x);
    // Y coordinate relative to the top side of the view.
    cefEvent.y = static_cast<float>(p->canvasSize().y - p->pos().y);
    // Radius in pixels. Set to 0 if not applicable.
    cefEvent.radius_x = cefEvent.radius_y = 0;
    // Radius in pixels. Set to 0 if not applicable.
    cefEvent.rotation_angle = 0;
    // The normalized pressure of the pointer input in the range of [0,1].
    cefEvent.pressure = static_cast<float>(p->pressure());
    // The state of the touch point. Touches begin with one CEF_TET_PRESSED event
    // followed by zero or more CEF_TET_MOVED events and finally one
    // CEF_TET_RELEASED or CEF_TET_CANCELLED event. Events not respecting this
    // order will be ignored.
    auto toCefEventType = [](auto state) -> cef_touch_event_type_t {
        switch (state) {
            case TouchState::None:
                return CEF_TET_CANCELLED;
            case TouchState::Started:
                return CEF_TET_PRESSED;
            case TouchState::Updated:
            case TouchState::Stationary:
                return CEF_TET_MOVED;
            case TouchState::Finished:
                return CEF_TET_RELEASED;
            default:  // Incorrect usage or new state added (warnings if left out)
                assert(false);
                return CEF_TET_CANCELLED;
        }
    };

    cefEvent.type = toCefEventType(p->state());
    auto toCefPointerType = [](auto device) -> cef_pointer_type_t {
        switch (device.getType()) {
            case TouchDevice::DeviceType::TouchScreen:
                return CEF_POINTER_TYPE_TOUCH;
            case TouchDevice::DeviceType::TouchPad:
                return CEF_POINTER_TYPE_MOUSE;
                // No types for these ones yet
                // case TouchDevice::DeviceType::Pen:
                //    return CEF_POINTER_TYPE_PEN;
                // case TouchDevice::DeviceType::Eraser:
                //    return CEF_POINTER_TYPE_ERASER;
            default:  // Incorrect usage or new state added (warnings if left out)
                assert(false);
                return CEF_POINTER_TYPE_TOUCH;
        }
    };
    cefEvent.pointer_type = toCefPointerType(*device);

    cefEvent.modifiers = modifiers_;
    return cefEvent;
}

CefKeyEvent CEFInteractionHandler::mapKeyEvent(const KeyboardEvent* e) {
    CefKeyEvent cefEvent;

    // TODO: Fix key code translation to match the ones used in CEF
    // cefEvent.type = e->state() & KeyState::Press ? KEYEVENT_RAWKEYDOWN : KEYEVENT_CHAR;
    cefEvent.type = e->state() & KeyState::Press ? KEYEVENT_KEYDOWN : KEYEVENT_KEYUP;
    // Convert character to UTF16
#if _MSC_VER
    // Linker error when using char16_t in visual studio
    // https://social.msdn.microsoft.com/Forums/vstudio/en-US/8f40dcd8-c67f-4eba-9134-a19b9178e481/vs-2015-rc-linker-stdcodecvt-error?forum=vcgeneral
    auto textUTF16 = std::wstring_convert<std::codecvt_utf8_utf16<uint16_t>, uint16_t>{}.from_bytes(
        e->text().data());
#else
    auto textUTF16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
        e->text().data());
#endif

    if (textUTF16.length() > 0) {
        cefEvent.character = textUTF16[0];
    } else {
        cefEvent.character = 0;
    }

    // Tested on Windows. You can test keys at
    // https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html
    // Compare the result with typing in Chrome
    cefEvent.windows_key_code = e->getNativeVirtualKey();
    // TODO: Get correct native_key_code, i.e. event LParam on Windows.
    // We might need the ScanCode sent by the system/Qt to get this.
    // An alternative would be to convert our the KeyEvent according to the Java KeyEvent, which
    // seem to be used by Chromium. See
    // https://docs.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html and
    // https://www.w3.org/TR/uievents-key/#named-key-attribute-values
    //
    // The native_key_code will be translated to DOM3 'code'
    // https://chromium.googlesource.com/chromium/src/+/master/ui/events/keycodes/dom/keycode_converter.h
    // According to this:
    // https://chromium.googlesource.com/chromium/src/+/master/ui/events/keycodes/dom/dom_key_data.inc
    // Note: native_key_code currently has no effect on text input fields, so text input will
    // display correctly.
    // cefEvent.native_key_code = TODO;

#ifdef _WINDOWS
    // F10 or ALT
    // https://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx
    cefEvent.is_system_key = (e->key() == IvwKey::F10) || (e->modifiers() & KeyModifier::Alt);
#else
    // Always false on non-windows platforms
    cefEvent.is_system_key = false;
#endif
    if (e->state() & KeyState::Press) {
        modifiers_ |= cef::keyModifiers(e->modifiers(), e->key());
    } else {
        modifiers_ &= ~cef::keyModifiers(e->modifiers(), e->key());
    }
    cefEvent.modifiers = modifiers_;
    return cefEvent;
}

void CEFInteractionHandler::updateMouseStates(MouseEvent* e) {
    if (e->state() & MouseState::Release) {
        // Remove modifiers
        modifiers_ &= ~(EVENTFLAG_LEFT_MOUSE_BUTTON | EVENTFLAG_MIDDLE_MOUSE_BUTTON |
                        EVENTFLAG_MIDDLE_MOUSE_BUTTON);
    } else {
        // Add modifiers
        modifiers_ |= (e->button() & MouseButton::Left ? EVENTFLAG_LEFT_MOUSE_BUTTON : 0) |
                      (e->button() & MouseButton::Middle ? EVENTFLAG_MIDDLE_MOUSE_BUTTON : 0) |
                      (e->button() & MouseButton::Right ? EVENTFLAG_RIGHT_MOUSE_BUTTON : 0);
    }
}
void CEFInteractionHandler::updateMouseStates(TouchEvent* e) {
    if (e->touchPoints().front().state() & TouchState::Finished) {
        // Remove modifiers
        modifiers_ &= ~(EVENTFLAG_LEFT_MOUSE_BUTTON | EVENTFLAG_MIDDLE_MOUSE_BUTTON |
                        EVENTFLAG_MIDDLE_MOUSE_BUTTON);
    } else {
        // Add modifiers
        modifiers_ |= (EVENTFLAG_LEFT_MOUSE_BUTTON);
    }
}
};  // namespace inviwo
<commit_msg>WebBrowser: mouse wheel fix, closes #1191<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2021 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/webbrowser/interaction/cefinteractionhandler.h>
#include <modules/webbrowser/interaction/cefkeyboardmapping.h>
#include <modules/webbrowser/renderhandlergl.h>
#include <inviwo/core/interaction/events/pickingevent.h>
#include <inviwo/core/interaction/events/resizeevent.h>
#include <inviwo/core/interaction/events/wheelevent.h>
#include <inviwo/core/interaction/events/touchevent.h>

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

namespace inviwo {

CEFInteractionHandler::CEFInteractionHandler(CefRefPtr<CefBrowserHost> host) : host_(host){};

void CEFInteractionHandler::invokeEvent(Event* event) {
    switch (event->hash()) {
        case ResizeEvent::chash(): {
            if (renderHandler_) {
                auto resizeEvent = static_cast<ResizeEvent*>(event);
                renderHandler_->updateCanvasSize(host_->GetBrowser(), resizeEvent->size());
                host_->WasResized();
            }
            break;
        }
        case KeyboardEvent::chash(): {
            auto keyEvent = event->getAs<KeyboardEvent>();
            auto cefEvent = mapKeyEvent(keyEvent);
            host_->SendKeyEvent(cefEvent);
            // Send CHAR event for characters, but not non-char keys like arrows,
            // function keys or clear.
            auto isCharacter = std::iscntrl(cefEvent.character) == 0;
            if (isCharacter && (keyEvent->state() & KeyState::Press)) {
                cefEvent.type = KEYEVENT_CHAR;
                // Fixes 'Legacy' key codes for keypress events at
                // https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html
                cefEvent.windows_key_code = cefEvent.character;
                host_->SendKeyEvent(cefEvent);
            }
            event->markAsUsed();
            break;
        }
    }
}

void CEFInteractionHandler::handlePickingEvent(PickingEvent* p) {
    if (p->getEvent()->hash() == MouseEvent::chash()) {
        auto mouseEvent = p->getEventAs<MouseEvent>();
        updateMouseStates(mouseEvent);
        auto cefMouseEvent = mapMouseEvent(mouseEvent);
        if (mouseEvent->state() & MouseState::Move) {
            bool mouseLeave = false;
            host_->SendMouseMoveEvent(cefMouseEvent, mouseLeave);
            p->markAsUsed();
        } else if (mouseEvent->state() & MouseState::Press ||
                   mouseEvent->state() & MouseState::Release) {
            CefBrowserHost::MouseButtonType type;

            if (mouseEvent->button() & MouseButton::Left) {
                type = MBT_LEFT;
            } else if (mouseEvent->button() & MouseButton::Middle) {
                type = MBT_MIDDLE;
            } else {  // if (mouseEvent->button() & MouseButton::Right) {
                type = MBT_RIGHT;
            }
            bool mouseUp = MouseState::Release & mouseEvent->state() ? true : false;
            int clickCount = MouseState::DoubleClick & mouseEvent->state() ? 2 : 1;
            host_->SendMouseClickEvent(cefMouseEvent, type, mouseUp, clickCount);
            p->markAsUsed();
        }
    } else if (auto touchEvent = p->getEventAs<TouchEvent>()) {

        if (!touchEvent->hasTouchPoints()) {
            return;
        }
        TouchDevice::DeviceType type = touchEvent->getDevice()
                                           ? touchEvent->getDevice()->getType()
                                           : TouchDevice::DeviceType::TouchScreen;
        if (type == TouchDevice::DeviceType::TouchPad) {
            // Mouse events are emulated on touch pads for single touch point
            // but we need still need to consume multi-touch events if user pressed on
            p->markAsUsed();
            return;
        }
        const auto& touchPoints = touchEvent->touchPoints();
        for (auto touchPoint : touchPoints) {
            auto cefEvent = mapTouchEvent(&touchPoint, touchEvent->getDevice());
            host_->SendTouchEvent(cefEvent);
        }
        p->markAsUsed();

    } else if (auto wheelEvent = p->getEventAs<WheelEvent>()) {
        auto cefMouseEvent = mapMouseEvent(wheelEvent);
        // cef expects the wheel delta in multiples of 120
        // see https://magpcss.org/ceforum/viewtopic.php?f=6&t=18203
        host_->SendMouseWheelEvent(cefMouseEvent, static_cast<int>(wheelEvent->delta().x * 120),
                                   static_cast<int>(wheelEvent->delta().y * 120));
        p->markAsUsed();
    }
}

CefMouseEvent CEFInteractionHandler::mapMouseEvent(const MouseInteractionEvent* e) {
    CefMouseEvent cefEvent;
    cefEvent.x = static_cast<int>(e->x());
    cefEvent.y = static_cast<int>(e->canvasSize().y) - static_cast<int>(e->y());
    cefEvent.modifiers = modifiers_;
    return cefEvent;
}

CefTouchEvent CEFInteractionHandler::mapTouchEvent(const TouchPoint* p, const TouchDevice* device) {
    CefTouchEvent cefEvent;
    cefEvent.id = p->id();
    // X coordinate relative to the left side of the view.
    cefEvent.x = static_cast<float>(p->pos().x);
    // Y coordinate relative to the top side of the view.
    cefEvent.y = static_cast<float>(p->canvasSize().y - p->pos().y);
    // Radius in pixels. Set to 0 if not applicable.
    cefEvent.radius_x = cefEvent.radius_y = 0;
    // Radius in pixels. Set to 0 if not applicable.
    cefEvent.rotation_angle = 0;
    // The normalized pressure of the pointer input in the range of [0,1].
    cefEvent.pressure = static_cast<float>(p->pressure());
    // The state of the touch point. Touches begin with one CEF_TET_PRESSED event
    // followed by zero or more CEF_TET_MOVED events and finally one
    // CEF_TET_RELEASED or CEF_TET_CANCELLED event. Events not respecting this
    // order will be ignored.
    auto toCefEventType = [](auto state) -> cef_touch_event_type_t {
        switch (state) {
            case TouchState::None:
                return CEF_TET_CANCELLED;
            case TouchState::Started:
                return CEF_TET_PRESSED;
            case TouchState::Updated:
            case TouchState::Stationary:
                return CEF_TET_MOVED;
            case TouchState::Finished:
                return CEF_TET_RELEASED;
            default:  // Incorrect usage or new state added (warnings if left out)
                assert(false);
                return CEF_TET_CANCELLED;
        }
    };

    cefEvent.type = toCefEventType(p->state());
    auto toCefPointerType = [](auto device) -> cef_pointer_type_t {
        switch (device.getType()) {
            case TouchDevice::DeviceType::TouchScreen:
                return CEF_POINTER_TYPE_TOUCH;
            case TouchDevice::DeviceType::TouchPad:
                return CEF_POINTER_TYPE_MOUSE;
                // No types for these ones yet
                // case TouchDevice::DeviceType::Pen:
                //    return CEF_POINTER_TYPE_PEN;
                // case TouchDevice::DeviceType::Eraser:
                //    return CEF_POINTER_TYPE_ERASER;
            default:  // Incorrect usage or new state added (warnings if left out)
                assert(false);
                return CEF_POINTER_TYPE_TOUCH;
        }
    };
    cefEvent.pointer_type = toCefPointerType(*device);

    cefEvent.modifiers = modifiers_;
    return cefEvent;
}

CefKeyEvent CEFInteractionHandler::mapKeyEvent(const KeyboardEvent* e) {
    CefKeyEvent cefEvent;

    // TODO: Fix key code translation to match the ones used in CEF
    // cefEvent.type = e->state() & KeyState::Press ? KEYEVENT_RAWKEYDOWN : KEYEVENT_CHAR;
    cefEvent.type = e->state() & KeyState::Press ? KEYEVENT_KEYDOWN : KEYEVENT_KEYUP;
    // Convert character to UTF16
#if _MSC_VER
    // Linker error when using char16_t in visual studio
    // https://social.msdn.microsoft.com/Forums/vstudio/en-US/8f40dcd8-c67f-4eba-9134-a19b9178e481/vs-2015-rc-linker-stdcodecvt-error?forum=vcgeneral
    auto textUTF16 = std::wstring_convert<std::codecvt_utf8_utf16<uint16_t>, uint16_t>{}.from_bytes(
        e->text().data());
#else
    auto textUTF16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
        e->text().data());
#endif

    if (textUTF16.length() > 0) {
        cefEvent.character = textUTF16[0];
    } else {
        cefEvent.character = 0;
    }

    // Tested on Windows. You can test keys at
    // https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html
    // Compare the result with typing in Chrome
    cefEvent.windows_key_code = e->getNativeVirtualKey();
    // TODO: Get correct native_key_code, i.e. event LParam on Windows.
    // We might need the ScanCode sent by the system/Qt to get this.
    // An alternative would be to convert our the KeyEvent according to the Java KeyEvent, which
    // seem to be used by Chromium. See
    // https://docs.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html and
    // https://www.w3.org/TR/uievents-key/#named-key-attribute-values
    //
    // The native_key_code will be translated to DOM3 'code'
    // https://chromium.googlesource.com/chromium/src/+/master/ui/events/keycodes/dom/keycode_converter.h
    // According to this:
    // https://chromium.googlesource.com/chromium/src/+/master/ui/events/keycodes/dom/dom_key_data.inc
    // Note: native_key_code currently has no effect on text input fields, so text input will
    // display correctly.
    // cefEvent.native_key_code = TODO;

#ifdef _WINDOWS
    // F10 or ALT
    // https://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx
    cefEvent.is_system_key = (e->key() == IvwKey::F10) || (e->modifiers() & KeyModifier::Alt);
#else
    // Always false on non-windows platforms
    cefEvent.is_system_key = false;
#endif
    if (e->state() & KeyState::Press) {
        modifiers_ |= cef::keyModifiers(e->modifiers(), e->key());
    } else {
        modifiers_ &= ~cef::keyModifiers(e->modifiers(), e->key());
    }
    cefEvent.modifiers = modifiers_;
    return cefEvent;
}

void CEFInteractionHandler::updateMouseStates(MouseEvent* e) {
    if (e->state() & MouseState::Release) {
        // Remove modifiers
        modifiers_ &= ~(EVENTFLAG_LEFT_MOUSE_BUTTON | EVENTFLAG_MIDDLE_MOUSE_BUTTON |
                        EVENTFLAG_MIDDLE_MOUSE_BUTTON);
    } else {
        // Add modifiers
        modifiers_ |= (e->button() & MouseButton::Left ? EVENTFLAG_LEFT_MOUSE_BUTTON : 0) |
                      (e->button() & MouseButton::Middle ? EVENTFLAG_MIDDLE_MOUSE_BUTTON : 0) |
                      (e->button() & MouseButton::Right ? EVENTFLAG_RIGHT_MOUSE_BUTTON : 0);
    }
}
void CEFInteractionHandler::updateMouseStates(TouchEvent* e) {
    if (e->touchPoints().front().state() & TouchState::Finished) {
        // Remove modifiers
        modifiers_ &= ~(EVENTFLAG_LEFT_MOUSE_BUTTON | EVENTFLAG_MIDDLE_MOUSE_BUTTON |
                        EVENTFLAG_MIDDLE_MOUSE_BUTTON);
    } else {
        // Add modifiers
        modifiers_ |= (EVENTFLAG_LEFT_MOUSE_BUTTON);
    }
}
};  // namespace inviwo
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2015-2016 Esteban Tovagliari, The appleseedhq Organization
//
// 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.
//

// Interface header.
#include "baserenderer.h"

// appleseed.renderer headers.
#include "renderer/global/globallogger.h"
#ifdef APPLESEED_WITH_OIIO
#include "renderer/kernel/rendering/oiioerrorhandler.h"
#endif
#ifdef APPLESEED_WITH_OSL
#include "renderer/kernel/rendering/rendererservices.h"
#include "renderer/kernel/shading/closures.h"
#endif
#include "renderer/modeling/project/project.h"
#include "renderer/modeling/scene/scene.h"

// appleseed.foundation headers.
#include "foundation/platform/compiler.h"

// Standard headers.
#include <cassert>
#include <exception>
#include <string>

using namespace foundation;
using namespace std;

namespace renderer
{

//
// BaseRenderer class implementation.
//

BaseRenderer::BaseRenderer(
    Project&                project,
    const ParamArray&       params)
  : m_project(project)
  , m_params(params)
{
#ifdef APPLESEED_WITH_OIIO
    m_error_handler = new OIIOErrorHandler();

#ifndef NDEBUG
    // While debugging, we want all possible outputs.
    m_error_handler->verbosity(OIIO::ErrorHandler::VERBOSE);
#endif

    RENDERER_LOG_DEBUG("creating openimageio texture system...");
    m_texture_system = OIIO::TextureSystem::create(false);

    m_texture_system->attribute("automip", 0);
    m_texture_system->attribute("accept_untiled", 1);
    m_texture_system->attribute("accept_unmipped", 1);
    m_texture_system->attribute("gray_to_rgb", 1);
    m_texture_system->attribute("latlong_up", "y");
#if OIIO_VERSION >= 10703
    m_texture_system->attribute("flip_t", 1);
#endif
#endif

#ifdef APPLESEED_WITH_OSL
    RENDERER_LOG_DEBUG("creating osl shading system...");
    m_renderer_services = new RendererServices(m_project, *m_texture_system);

#if OSL_LIBRARY_VERSION_CODE >= 10700
    m_shading_system = new OSL::ShadingSystem(
#else
    m_shading_system = OSL::ShadingSystem::create(
#endif
        m_renderer_services,
        m_texture_system,
        m_error_handler);

    m_shading_system->attribute("lockgeom", 1);
    m_shading_system->attribute("colorspace", "Linear");
    m_shading_system->attribute("commonspace", "world");
    m_shading_system->attribute("statistics:level", 1);

    m_shading_system->attribute(
        "raytypes",
        OSL::TypeDesc(
            OSL::TypeDesc::STRING,
            static_cast<int>(VisibilityFlags::Count)),
        VisibilityFlags::Names);

#ifndef NDEBUG
    // While debugging, we want all possible outputs.
    m_shading_system->attribute("debug", 1);
    m_shading_system->attribute("compile_report", 1);
    m_shading_system->attribute("countlayerexecs", 1);
    m_shading_system->attribute("clearmemory", 1);
#endif

    // Register appleseed's closures into OSL's shading system.
    register_closures(*m_shading_system);
#endif
}

BaseRenderer::~BaseRenderer()
{
#ifdef APPLESEED_WITH_OSL
    RENDERER_LOG_DEBUG("destroying osl shading system...");
    m_project.get_scene()->release_optimized_osl_shader_groups();

#if OSL_LIBRARY_VERSION_CODE >= 10700
    delete m_shading_system;
#else
    OSL::ShadingSystem::destroy(m_shading_system);
#endif

    delete m_renderer_services;
#endif

#ifdef APPLESEED_WITH_OIIO
    const string stats = m_texture_system->getstats();
    const string trimmed_stats = trim_right(stats, "\r\n");
    RENDERER_LOG_INFO("%s", trimmed_stats.c_str());

    RENDERER_LOG_DEBUG("destroying openimageio texture system...");
    OIIO::TextureSystem::destroy(m_texture_system);
    delete m_error_handler;
#endif
}

ParamArray& BaseRenderer::get_parameters()
{
    return m_params;
}

const ParamArray& BaseRenderer::get_parameters() const
{
    return m_params;
}

bool BaseRenderer::initialize_shading_system(
    TextureStore& texture_store,
    IAbortSwitch& abort_switch)
{
#ifdef APPLESEED_WITH_OIIO
    initialize_oiio();
#endif

#ifdef APPLESEED_WITH_OSL
    return initialize_osl(texture_store, abort_switch);
#else
    return true;
#endif
}

#ifdef APPLESEED_WITH_OIIO

void BaseRenderer::initialize_oiio()
{
    const ParamArray& params = m_params.child("texture_store");

    const size_t texture_cache_size_bytes =
        params.get_optional<size_t>("max_size", 256 * 1024 * 1024);

    RENDERER_LOG_INFO(
        "setting openimageio texture cache size to %s.",
        pretty_size(texture_cache_size_bytes).c_str());

    const float texture_cache_size_mb =
        static_cast<float>(texture_cache_size_bytes) / (1024 * 1024);

    m_texture_system->attribute("max_memory_MB", texture_cache_size_mb);

    // search paths
    string prev_search_path;
    m_texture_system->getattribute("searchpath", prev_search_path);
    const string new_search_path = m_project.make_search_path_string();

    if (new_search_path != prev_search_path)
    {
        RENDERER_LOG_INFO(
            "setting openimageio search path to %s.",
            new_search_path.c_str());

        m_texture_system->clear();
        m_texture_system->attribute("searchpath", new_search_path);
    }
}

#endif

#ifdef APPLESEED_WITH_OSL

bool BaseRenderer::initialize_osl(TextureStore& texture_store, IAbortSwitch& abort_switch)
{
    m_renderer_services->initialize(texture_store);

    // search paths
    string prev_search_path;
    m_shading_system->getattribute("searchpath:shader", prev_search_path);
    const string new_search_path = m_project.make_search_path_string();

    if (new_search_path != prev_search_path)
    {
        RENDERER_LOG_INFO(
            "setting osl shader search path to %s.",
            new_search_path.c_str());

        m_project.get_scene()->release_optimized_osl_shader_groups();
        m_shading_system->attribute("searchpath:shader", new_search_path);
    }

    // Re-optimize the shader groups that need updating.
    return
        m_project.get_scene()->create_optimized_osl_shader_groups(
            *m_shading_system,
            &abort_switch);
}

#endif

}   // namespace renderer
<commit_msg>Disable high volume OSL logs in debug<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2015-2016 Esteban Tovagliari, The appleseedhq Organization
//
// 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.
//

// Interface header.
#include "baserenderer.h"

// appleseed.renderer headers.
#include "renderer/global/globallogger.h"
#ifdef APPLESEED_WITH_OIIO
#include "renderer/kernel/rendering/oiioerrorhandler.h"
#endif
#ifdef APPLESEED_WITH_OSL
#include "renderer/kernel/rendering/rendererservices.h"
#include "renderer/kernel/shading/closures.h"
#endif
#include "renderer/modeling/project/project.h"
#include "renderer/modeling/scene/scene.h"

// appleseed.foundation headers.
#include "foundation/platform/compiler.h"

// Standard headers.
#include <cassert>
#include <exception>
#include <string>

using namespace foundation;
using namespace std;

namespace renderer
{

//
// BaseRenderer class implementation.
//

BaseRenderer::BaseRenderer(
    Project&                project,
    const ParamArray&       params)
  : m_project(project)
  , m_params(params)
{
#ifdef APPLESEED_WITH_OIIO
    m_error_handler = new OIIOErrorHandler();

#ifndef NDEBUG
    // While debugging, we want all possible outputs.
    m_error_handler->verbosity(OIIO::ErrorHandler::VERBOSE);
#endif

    RENDERER_LOG_DEBUG("creating openimageio texture system...");
    m_texture_system = OIIO::TextureSystem::create(false);

    m_texture_system->attribute("automip", 0);
    m_texture_system->attribute("accept_untiled", 1);
    m_texture_system->attribute("accept_unmipped", 1);
    m_texture_system->attribute("gray_to_rgb", 1);
    m_texture_system->attribute("latlong_up", "y");
#if OIIO_VERSION >= 10703
    m_texture_system->attribute("flip_t", 1);
#endif
#endif

#ifdef APPLESEED_WITH_OSL
    RENDERER_LOG_DEBUG("creating osl shading system...");
    m_renderer_services = new RendererServices(m_project, *m_texture_system);

#if OSL_LIBRARY_VERSION_CODE >= 10700
    m_shading_system = new OSL::ShadingSystem(
#else
    m_shading_system = OSL::ShadingSystem::create(
#endif
        m_renderer_services,
        m_texture_system,
        m_error_handler);

    m_shading_system->attribute("lockgeom", 1);
    m_shading_system->attribute("colorspace", "Linear");
    m_shading_system->attribute("commonspace", "world");
    m_shading_system->attribute("statistics:level", 1);

    m_shading_system->attribute(
        "raytypes",
        OSL::TypeDesc(
            OSL::TypeDesc::STRING,
            static_cast<int>(VisibilityFlags::Count)),
        VisibilityFlags::Names);

#ifndef NDEBUG
    m_shading_system->attribute("compile_report", 1);
    m_shading_system->attribute("countlayerexecs", 1);
    m_shading_system->attribute("clearmemory", 1);
#endif

    // Register appleseed's closures into OSL's shading system.
    register_closures(*m_shading_system);
#endif
}

BaseRenderer::~BaseRenderer()
{
#ifdef APPLESEED_WITH_OSL
    RENDERER_LOG_DEBUG("destroying osl shading system...");
    m_project.get_scene()->release_optimized_osl_shader_groups();

#if OSL_LIBRARY_VERSION_CODE >= 10700
    delete m_shading_system;
#else
    OSL::ShadingSystem::destroy(m_shading_system);
#endif

    delete m_renderer_services;
#endif

#ifdef APPLESEED_WITH_OIIO
    const string stats = m_texture_system->getstats();
    const string trimmed_stats = trim_right(stats, "\r\n");
    RENDERER_LOG_INFO("%s", trimmed_stats.c_str());

    RENDERER_LOG_DEBUG("destroying openimageio texture system...");
    OIIO::TextureSystem::destroy(m_texture_system);
    delete m_error_handler;
#endif
}

ParamArray& BaseRenderer::get_parameters()
{
    return m_params;
}

const ParamArray& BaseRenderer::get_parameters() const
{
    return m_params;
}

bool BaseRenderer::initialize_shading_system(
    TextureStore& texture_store,
    IAbortSwitch& abort_switch)
{
#ifdef APPLESEED_WITH_OIIO
    initialize_oiio();
#endif

#ifdef APPLESEED_WITH_OSL
    return initialize_osl(texture_store, abort_switch);
#else
    return true;
#endif
}

#ifdef APPLESEED_WITH_OIIO

void BaseRenderer::initialize_oiio()
{
    const ParamArray& params = m_params.child("texture_store");

    const size_t texture_cache_size_bytes =
        params.get_optional<size_t>("max_size", 256 * 1024 * 1024);

    RENDERER_LOG_INFO(
        "setting openimageio texture cache size to %s.",
        pretty_size(texture_cache_size_bytes).c_str());

    const float texture_cache_size_mb =
        static_cast<float>(texture_cache_size_bytes) / (1024 * 1024);

    m_texture_system->attribute("max_memory_MB", texture_cache_size_mb);

    // search paths
    string prev_search_path;
    m_texture_system->getattribute("searchpath", prev_search_path);
    const string new_search_path = m_project.make_search_path_string();

    if (new_search_path != prev_search_path)
    {
        RENDERER_LOG_INFO(
            "setting openimageio search path to %s.",
            new_search_path.c_str());

        m_texture_system->clear();
        m_texture_system->attribute("searchpath", new_search_path);
    }
}

#endif

#ifdef APPLESEED_WITH_OSL

bool BaseRenderer::initialize_osl(TextureStore& texture_store, IAbortSwitch& abort_switch)
{
    m_renderer_services->initialize(texture_store);

    // search paths
    string prev_search_path;
    m_shading_system->getattribute("searchpath:shader", prev_search_path);
    const string new_search_path = m_project.make_search_path_string();

    if (new_search_path != prev_search_path)
    {
        RENDERER_LOG_INFO(
            "setting osl shader search path to %s.",
            new_search_path.c_str());

        m_project.get_scene()->release_optimized_osl_shader_groups();
        m_shading_system->attribute("searchpath:shader", new_search_path);
    }

    // Re-optimize the shader groups that need updating.
    return
        m_project.get_scene()->create_optimized_osl_shader_groups(
            *m_shading_system,
            &abort_switch);
}

#endif

}   // namespace renderer
<|endoftext|>