<commit_before>/*
 * Copyright (c) 2018 https://www.thecoderscorner.com (Dave Cherry).
 * This product is licensed under an Apache license, see the LICENSE file in the top-level directory.
 */

#include <IoAbstractionWire.h>

PCF8574IoAbstraction::PCF8574IoAbstraction(uint8_t addr, uint8_t interruptPin, WireType wireImplementation, bool mode16Bit) : lastRead{}, toWrite{} {
	this->wireImpl = wireImplementation;
	this->address = addr;
	this->interruptPin = interruptPin;
    flags = 0;
    bitWrite(flags, NEEDS_WRITE_FLAG, true);
    bitWrite(flags, PCF8575_16BIT_FLAG, mode16Bit);

}

void PCF8574IoAbstraction::pinDirection(pinid_t pin, uint8_t mode) {
	if (mode == INPUT || mode == INPUT_PULLUP) {
		overrideReadFlag();
		writeValue(pin, HIGH);
	}
	else {
		writeValue(pin, LOW);
	}
    bitWrite(flags, NEEDS_WRITE_FLAG, true);
}

void PCF8574IoAbstraction::writeValue(pinid_t pin, uint8_t value) {
    int port = (pin > 7) ? 1 : 0;
	bitWrite(toWrite[port], (pin % 8), value);
    bitWrite(flags, NEEDS_WRITE_FLAG, true);
}

uint8_t PCF8574IoAbstraction::readValue(pinid_t pin) {
    int port = (pin > 7) ? 1 : 0;
    return (lastRead[port] & (1 << pin)) ? HIGH : LOW;
}

uint8_t PCF8574IoAbstraction::readPort(pinid_t pin) {
    int port = (pin > 7) ? 1 : 0;
    return lastRead[port];
}

void PCF8574IoAbstraction::writePort(pinid_t pin, uint8_t value) {
    int port = (pin > 7) ? 1 : 0;
    toWrite[port] = value;
    bitWrite(flags, NEEDS_WRITE_FLAG, true);
}

bool PCF8574IoAbstraction::runLoop(){
    bool writeOk = true;
    size_t bytesToTransfer = bitRead(flags, PCF8575_16BIT_FLAG) ? 2 : 1;
    if (bitRead(flags, NEEDS_WRITE_FLAG)) {
        bitWrite(flags, NEEDS_WRITE_FLAG, false);
        writeOk = ioaWireWriteWithRetry(wireImpl, address, toWrite, bytesToTransfer);
    }

    if(bitRead(flags, PINS_CONFIGURED_READ_FLAG)) {
        writeOk = writeOk && ioaWireRead(wireImpl, address, lastRead, bytesToTransfer);
    }
    return writeOk;
}

void PCF8574IoAbstraction::attachInterrupt(pinid_t /*pin*/, RawIntHandler intHandler, uint8_t /*mode*/) {
	// if there's an interrupt pin set
	if(interruptPin == 0xff) return;

	internalDigitalIo()->pinDirection(interruptPin, INPUT_PULLUP);
	internalDigitalIo()->attachInterrupt(interruptPin, intHandler, FALLING);
}

BasicIoAbstraction* ioFrom8574(uint8_t addr, pinid_t interruptPin, WireType wireImpl) {
	return new PCF8574IoAbstraction(addr, interruptPin, wireImpl);
}

BasicIoAbstraction* ioFrom8575(uint8_t addr, pinid_t interruptPin, WireType wireImpl) {
    return new PCF8574IoAbstraction(addr, interruptPin, wireImpl, true);
}

MCP23017IoAbstraction::MCP23017IoAbstraction(uint8_t address, Mcp23xInterruptMode intMode, pinid_t intPinA, pinid_t intPinB, WireType wireImpl) {
	this->wireImpl = wireImpl;
	this->address = address;
	this->intPinA = intPinA;
	this->intPinB = intPinB;
	this->intMode = intMode;
	this->toWrite = this->lastRead = 0;
	this->needsInit = true;
	this->portFlags = 0;
}

void MCP23017IoAbstraction::initDevice() {
	uint8_t controlReg = (readFromDevice(IOCON_ADDR) & 0xff);

	if(intPinB == 0xff && intPinA != 0xff) {
		bitSet(controlReg, IOCON_MIRROR_BIT);
	}
	else if(intPinA != 0xff) {
		bitClear(controlReg, IOCON_MIRROR_BIT);
	}

	bitClear(controlReg, IOCON_BANK_BIT);
	bitClear(controlReg, IOCON_SEQOP_BIT);

	uint16_t regToWrite = controlReg | (((uint16_t)controlReg) << 8U);
	writeToDevice(IOCON_ADDR, regToWrite);

	portFlags = 0;
	needsInit = false;
}

void MCP23017IoAbstraction::toggleBitInRegister(uint8_t regAddr, uint8_t theBit, bool value) {
	uint16_t reg = readFromDevice(regAddr);
	bitWrite(reg, theBit, value);

	// for debugging to see the commands being sent, uncomment below
	//serdebugF4("toggle(regAddr, bit, toggle): ", regAddr, theBit, value);
	//serdebugFHex("Value: ", reg);
	// end debugging code

	writeToDevice(regAddr, reg);
}

void MCP23017IoAbstraction::pinDirection(pinid_t pin, uint8_t mode) {
	if(needsInit) initDevice();

	toggleBitInRegister(IODIR_ADDR, pin, (mode == INPUT || mode == INPUT_PULLUP));
	toggleBitInRegister(GPPU_ADDR, pin, mode == INPUT_PULLUP);

	bitSet(portFlags, (pin < 8) ? READER_PORTA_BIT : READER_PORTB_BIT);
}

void MCP23017IoAbstraction::writeValue(pinid_t pin, uint8_t value) {
	if(needsInit) initDevice();

	bitWrite(toWrite, pin, value);
	bitSet(portFlags, (pin < 8) ? CHANGE_PORTA_BIT : CHANGE_PORTB_BIT);
}

uint8_t MCP23017IoAbstraction::readValue(pinid_t pin) {
	return bitRead(lastRead, pin);
}

uint8_t MCP23017IoAbstraction::readPort(pinid_t pin) {
	return (pin < 8) ? (lastRead & 0xff) : (lastRead >> 8);
}

void MCP23017IoAbstraction::writePort(pinid_t pin, uint8_t value) {
	if(pin < 8) {
		toWrite &= 0xff00;
		toWrite |= value;
		bitSet(portFlags, CHANGE_PORTA_BIT);
	}
	else {
		toWrite &= 0x00ff;
		toWrite |= ((uint16_t)value << 8);
		bitSet(portFlags, CHANGE_PORTB_BIT);
	}
}

bool MCP23017IoAbstraction::runLoop() {
	if(needsInit) initDevice();

	bool writeOk = true;

	bool flagA = bitRead(portFlags, CHANGE_PORTA_BIT);
	bool flagB = bitRead(portFlags, CHANGE_PORTB_BIT);
	if(flagA && flagB) // write on both ports
		writeOk = writeToDevice(OUTLAT_ADDR, toWrite);
	else if(flagA)
		writeOk = writeToDevice8(OUTLAT_ADDR, toWrite);
	else if(flagB)
		writeOk = writeToDevice8(OUTLAT_ADDR + 1, toWrite >> 8);

	bitClear(portFlags, CHANGE_PORTA_BIT);
	bitClear(portFlags, CHANGE_PORTB_BIT);

	flagA = bitRead(portFlags, READER_PORTA_BIT);
	flagB = bitRead(portFlags, READER_PORTB_BIT);
	if(flagA && flagB)
		lastRead = readFromDevice(GPIO_ADDR);
	else if(flagA)
		lastRead = readFromDevice8(GPIO_ADDR);
	else if(flagB)
		lastRead = readFromDevice8(GPIO_ADDR + 1) << 8U;

	return writeOk;
}

bool MCP23017IoAbstraction::writeToDevice(uint8_t reg, uint16_t command) {
	uint8_t data[3];
	data[0] = reg;
    data[1] = (uint8_t)command;
    data[2] = (uint8_t)(command>>8);
	return ioaWireWriteWithRetry(wireImpl, address, data, sizeof data);
}

bool MCP23017IoAbstraction::writeToDevice8(uint8_t reg, uint8_t command) {
    uint8_t data[2];
    data[0] = reg;
    data[1] = (uint8_t)command;
    return ioaWireWriteWithRetry(wireImpl, address, data, sizeof data);
}

uint16_t MCP23017IoAbstraction::readFromDevice(uint8_t reg) {
	ioaWireWriteWithRetry(wireImpl, address, &reg, 1, 0, false);

	uint8_t data[2];
	ioaWireRead(wireImpl, address, data, sizeof data);
	// read will get port A first then port B.
	uint8_t portA = data[0];
	uint16_t portB = data[1] << 8U;
	return portA | portB;
}

uint8_t MCP23017IoAbstraction::readFromDevice8(uint8_t reg) {
    ioaWireWriteWithRetry(wireImpl, address, &reg, 1, 0);

	uint8_t buffer[2];
    if(ioaWireRead(wireImpl, address, buffer, 1)){
       return buffer[0];
    }
    return 0;
}

void MCP23017IoAbstraction::attachInterrupt(pinid_t pin, RawIntHandler intHandler, uint8_t mode) {
	// only if there's an interrupt pin set
	if(intPinA == 0xff) return;

	auto  inbuiltIo = internalDigitalIo();
	uint8_t pm = (intMode == ACTIVE_HIGH_OPEN || intMode == ACTIVE_LOW_OPEN) ? INPUT_PULLUP : INPUT;
	uint8_t im = (intMode == ACTIVE_HIGH || intMode == ACTIVE_HIGH_OPEN) ? RISING : FALLING;
	if(intPinB == 0xff) {
        inbuiltIo->pinDirection(intPinA, pm);
        inbuiltIo->attachInterrupt(intPinA, intHandler, im);
	}
	else {
        inbuiltIo->pinDirection(intPinA, pm);
        inbuiltIo->attachInterrupt(intPinA, intHandler, im);
        inbuiltIo->pinDirection(intPinB, pm);
        inbuiltIo->attachInterrupt(intPinB, intHandler, im);
    }

	toggleBitInRegister(GPINTENA_ADDR, pin, true);
	toggleBitInRegister(INTCON_ADDR, pin, mode != CHANGE);
	toggleBitInRegister(DEFVAL_ADDR, pin, mode == FALLING);
}

void MCP23017IoAbstraction::setInvertInputPin(pinid_t pin, bool shouldInvert) {
    toggleBitInRegister(IPOL_ADDR, pin, shouldInvert);
}

IoAbstractionRef ioFrom23017(pinid_t addr, WireType wireImpl) {
	return ioFrom23017IntPerPort(addr, NOT_ENABLED, 0xff, 0xff, wireImpl);
}

IoAbstractionRef ioFrom23017(uint8_t addr, Mcp23xInterruptMode intMode, pinid_t interruptPin, WireType wireImpl) {
	return ioFrom23017IntPerPort(addr, intMode, interruptPin, 0xff, wireImpl);
}

IoAbstractionRef ioFrom23017IntPerPort(pinid_t addr, Mcp23xInterruptMode intMode, pinid_t intPinA, pinid_t intPinB, WireType wireImpl) {
	return new MCP23017IoAbstraction(addr, intMode, intPinA, intPinB, wireImpl);
}<commit_msg>[PCF8575] Correctly read values above first byte<commit_after>/*
 * Copyright (c) 2018 https://www.thecoderscorner.com (Dave Cherry).
 * This product is licensed under an Apache license, see the LICENSE file in the top-level directory.
 */

#include <IoAbstractionWire.h>

PCF8574IoAbstraction::PCF8574IoAbstraction(uint8_t addr, uint8_t interruptPin, WireType wireImplementation, bool mode16Bit) : lastRead{}, toWrite{} {
	this->wireImpl = wireImplementation;
	this->address = addr;
	this->interruptPin = interruptPin;
    flags = 0;
    bitWrite(flags, NEEDS_WRITE_FLAG, true);
    bitWrite(flags, PCF8575_16BIT_FLAG, mode16Bit);

}

void PCF8574IoAbstraction::pinDirection(pinid_t pin, uint8_t mode) {
	if (mode == INPUT || mode == INPUT_PULLUP) {
		overrideReadFlag();
		writeValue(pin, HIGH);
	}
	else {
		writeValue(pin, LOW);
	}
    bitWrite(flags, NEEDS_WRITE_FLAG, true);
}

void PCF8574IoAbstraction::writeValue(pinid_t pin, uint8_t value) {
    int port = (pin > 7) ? 1 : 0;
	bitWrite(toWrite[port], (pin % 8), value);
    bitWrite(flags, NEEDS_WRITE_FLAG, true);
}

uint8_t PCF8574IoAbstraction::readValue(pinid_t pin) {
    int port = (pin > 7) ? 1 : 0;
    return (lastRead[port] & (1 << (pin % 8))) ? HIGH : LOW;
}

uint8_t PCF8574IoAbstraction::readPort(pinid_t pin) {
    int port = (pin > 7) ? 1 : 0;
    return lastRead[port];
}

void PCF8574IoAbstraction::writePort(pinid_t pin, uint8_t value) {
    int port = (pin > 7) ? 1 : 0;
    toWrite[port] = value;
    bitWrite(flags, NEEDS_WRITE_FLAG, true);
}

bool PCF8574IoAbstraction::runLoop(){
    bool writeOk = true;
    size_t bytesToTransfer = bitRead(flags, PCF8575_16BIT_FLAG) ? 2 : 1;
    if (bitRead(flags, NEEDS_WRITE_FLAG)) {
        bitWrite(flags, NEEDS_WRITE_FLAG, false);
        writeOk = ioaWireWriteWithRetry(wireImpl, address, toWrite, bytesToTransfer);
    }

    if(bitRead(flags, PINS_CONFIGURED_READ_FLAG)) {
        writeOk = writeOk && ioaWireRead(wireImpl, address, lastRead, bytesToTransfer);
    }
    return writeOk;
}

void PCF8574IoAbstraction::attachInterrupt(pinid_t /*pin*/, RawIntHandler intHandler, uint8_t /*mode*/) {
	// if there's an interrupt pin set
	if(interruptPin == 0xff) return;

	internalDigitalIo()->pinDirection(interruptPin, INPUT_PULLUP);
	internalDigitalIo()->attachInterrupt(interruptPin, intHandler, FALLING);
}

BasicIoAbstraction* ioFrom8574(uint8_t addr, pinid_t interruptPin, WireType wireImpl) {
	return new PCF8574IoAbstraction(addr, interruptPin, wireImpl);
}

BasicIoAbstraction* ioFrom8575(uint8_t addr, pinid_t interruptPin, WireType wireImpl) {
    return new PCF8574IoAbstraction(addr, interruptPin, wireImpl, true);
}

MCP23017IoAbstraction::MCP23017IoAbstraction(uint8_t address, Mcp23xInterruptMode intMode, pinid_t intPinA, pinid_t intPinB, WireType wireImpl) {
	this->wireImpl = wireImpl;
	this->address = address;
	this->intPinA = intPinA;
	this->intPinB = intPinB;
	this->intMode = intMode;
	this->toWrite = this->lastRead = 0;
	this->needsInit = true;
	this->portFlags = 0;
}

void MCP23017IoAbstraction::initDevice() {
	uint8_t controlReg = (readFromDevice(IOCON_ADDR) & 0xff);

	if(intPinB == 0xff && intPinA != 0xff) {
		bitSet(controlReg, IOCON_MIRROR_BIT);
	}
	else if(intPinA != 0xff) {
		bitClear(controlReg, IOCON_MIRROR_BIT);
	}

	bitClear(controlReg, IOCON_BANK_BIT);
	bitClear(controlReg, IOCON_SEQOP_BIT);

	uint16_t regToWrite = controlReg | (((uint16_t)controlReg) << 8U);
	writeToDevice(IOCON_ADDR, regToWrite);

	portFlags = 0;
	needsInit = false;
}

void MCP23017IoAbstraction::toggleBitInRegister(uint8_t regAddr, uint8_t theBit, bool value) {
	uint16_t reg = readFromDevice(regAddr);
	bitWrite(reg, theBit, value);

	// for debugging to see the commands being sent, uncomment below
	//serdebugF4("toggle(regAddr, bit, toggle): ", regAddr, theBit, value);
	//serdebugFHex("Value: ", reg);
	// end debugging code

	writeToDevice(regAddr, reg);
}

void MCP23017IoAbstraction::pinDirection(pinid_t pin, uint8_t mode) {
	if(needsInit) initDevice();

	toggleBitInRegister(IODIR_ADDR, pin, (mode == INPUT || mode == INPUT_PULLUP));
	toggleBitInRegister(GPPU_ADDR, pin, mode == INPUT_PULLUP);

	bitSet(portFlags, (pin < 8) ? READER_PORTA_BIT : READER_PORTB_BIT);
}

void MCP23017IoAbstraction::writeValue(pinid_t pin, uint8_t value) {
	if(needsInit) initDevice();

	bitWrite(toWrite, pin, value);
	bitSet(portFlags, (pin < 8) ? CHANGE_PORTA_BIT : CHANGE_PORTB_BIT);
}

uint8_t MCP23017IoAbstraction::readValue(pinid_t pin) {
	return bitRead(lastRead, pin);
}

uint8_t MCP23017IoAbstraction::readPort(pinid_t pin) {
	return (pin < 8) ? (lastRead & 0xff) : (lastRead >> 8);
}

void MCP23017IoAbstraction::writePort(pinid_t pin, uint8_t value) {
	if(pin < 8) {
		toWrite &= 0xff00;
		toWrite |= value;
		bitSet(portFlags, CHANGE_PORTA_BIT);
	}
	else {
		toWrite &= 0x00ff;
		toWrite |= ((uint16_t)value << 8);
		bitSet(portFlags, CHANGE_PORTB_BIT);
	}
}

bool MCP23017IoAbstraction::runLoop() {
	if(needsInit) initDevice();

	bool writeOk = true;

	bool flagA = bitRead(portFlags, CHANGE_PORTA_BIT);
	bool flagB = bitRead(portFlags, CHANGE_PORTB_BIT);
	if(flagA && flagB) // write on both ports
		writeOk = writeToDevice(OUTLAT_ADDR, toWrite);
	else if(flagA)
		writeOk = writeToDevice8(OUTLAT_ADDR, toWrite);
	else if(flagB)
		writeOk = writeToDevice8(OUTLAT_ADDR + 1, toWrite >> 8);

	bitClear(portFlags, CHANGE_PORTA_BIT);
	bitClear(portFlags, CHANGE_PORTB_BIT);

	flagA = bitRead(portFlags, READER_PORTA_BIT);
	flagB = bitRead(portFlags, READER_PORTB_BIT);
	if(flagA && flagB)
		lastRead = readFromDevice(GPIO_ADDR);
	else if(flagA)
		lastRead = readFromDevice8(GPIO_ADDR);
	else if(flagB)
		lastRead = readFromDevice8(GPIO_ADDR + 1) << 8U;

	return writeOk;
}

bool MCP23017IoAbstraction::writeToDevice(uint8_t reg, uint16_t command) {
	uint8_t data[3];
	data[0] = reg;
    data[1] = (uint8_t)command;
    data[2] = (uint8_t)(command>>8);
	return ioaWireWriteWithRetry(wireImpl, address, data, sizeof data);
}

bool MCP23017IoAbstraction::writeToDevice8(uint8_t reg, uint8_t command) {
    uint8_t data[2];
    data[0] = reg;
    data[1] = (uint8_t)command;
    return ioaWireWriteWithRetry(wireImpl, address, data, sizeof data);
}

uint16_t MCP23017IoAbstraction::readFromDevice(uint8_t reg) {
	ioaWireWriteWithRetry(wireImpl, address, &reg, 1, 0, false);

	uint8_t data[2];
	ioaWireRead(wireImpl, address, data, sizeof data);
	// read will get port A first then port B.
	uint8_t portA = data[0];
	uint16_t portB = data[1] << 8U;
	return portA | portB;
}

uint8_t MCP23017IoAbstraction::readFromDevice8(uint8_t reg) {
    ioaWireWriteWithRetry(wireImpl, address, &reg, 1, 0);

	uint8_t buffer[2];
    if(ioaWireRead(wireImpl, address, buffer, 1)){
       return buffer[0];
    }
    return 0;
}

void MCP23017IoAbstraction::attachInterrupt(pinid_t pin, RawIntHandler intHandler, uint8_t mode) {
	// only if there's an interrupt pin set
	if(intPinA == 0xff) return;

	auto  inbuiltIo = internalDigitalIo();
	uint8_t pm = (intMode == ACTIVE_HIGH_OPEN || intMode == ACTIVE_LOW_OPEN) ? INPUT_PULLUP : INPUT;
	uint8_t im = (intMode == ACTIVE_HIGH || intMode == ACTIVE_HIGH_OPEN) ? RISING : FALLING;
	if(intPinB == 0xff) {
        inbuiltIo->pinDirection(intPinA, pm);
        inbuiltIo->attachInterrupt(intPinA, intHandler, im);
	}
	else {
        inbuiltIo->pinDirection(intPinA, pm);
        inbuiltIo->attachInterrupt(intPinA, intHandler, im);
        inbuiltIo->pinDirection(intPinB, pm);
        inbuiltIo->attachInterrupt(intPinB, intHandler, im);
    }

	toggleBitInRegister(GPINTENA_ADDR, pin, true);
	toggleBitInRegister(INTCON_ADDR, pin, mode != CHANGE);
	toggleBitInRegister(DEFVAL_ADDR, pin, mode == FALLING);
}

void MCP23017IoAbstraction::setInvertInputPin(pinid_t pin, bool shouldInvert) {
    toggleBitInRegister(IPOL_ADDR, pin, shouldInvert);
}

IoAbstractionRef ioFrom23017(pinid_t addr, WireType wireImpl) {
	return ioFrom23017IntPerPort(addr, NOT_ENABLED, 0xff, 0xff, wireImpl);
}

IoAbstractionRef ioFrom23017(uint8_t addr, Mcp23xInterruptMode intMode, pinid_t interruptPin, WireType wireImpl) {
	return ioFrom23017IntPerPort(addr, intMode, interruptPin, 0xff, wireImpl);
}

IoAbstractionRef ioFrom23017IntPerPort(pinid_t addr, Mcp23xInterruptMode intMode, pinid_t intPinA, pinid_t intPinB, WireType wireImpl) {
	return new MCP23017IoAbstraction(addr, intMode, intPinA, intPinB, wireImpl);
}<|endoftext|>


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

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.0.0, packaged on August, 2008.

 http://glc-lib.sourceforge.net

 GLC-lib is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 GLC-lib is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/

//! \file glc_vbogeom.cpp Implementation of the GLC_VboGeom class.

#include "glc_vbogeom.h"
#include "glc_openglexception.h"
#include "glc_selectionmaterial.h"

//////////////////////////////////////////////////////////////////////
// Constructor destructor
//////////////////////////////////////////////////////////////////////
// Default constructor
GLC_VboGeom::GLC_VboGeom(const QString& name, const bool typeIsWire)
:GLC_Object(name)
, m_VboId(0)
, m_IboId(0)
, m_GeometryIsValid(false)	// By default geometry is invalid
, m_pMaterial(NULL)			// have to be set later in constructor
, m_UseColorPerVertex(false)
, m_IsWire(typeIsWire)		// the geometry type
, m_IsTransparent(false)	// Not transparent by default
{
	// Material is set here
	setMaterial(new GLC_Material());
}
// Copy constructor
GLC_VboGeom::GLC_VboGeom(const GLC_VboGeom& sourceGeom)
:GLC_Object(sourceGeom)
, m_VboId(0)
, m_IboId(0)
, m_GeometryIsValid(false)	// By default geometry is invalid
, m_pMaterial(NULL)			// have to be set later in constructor
, m_UseColorPerVertex(sourceGeom.m_UseColorPerVertex)
, m_IsWire(sourceGeom.m_IsWire)
, m_IsTransparent(sourceGeom.m_IsTransparent)
{
	m_Uid= glc::GLC_GenID();
	// Material is copy here
	setMaterial(new GLC_Material());
	m_pMaterial->setMaterial(sourceGeom.getMaterial());
}

GLC_VboGeom::~GLC_VboGeom()
{
	// VBO
	if (0 != m_VboId)
		glDeleteBuffers(1, &m_VboId);
	// IBO
	if (0 != m_IboId)
		glDeleteBuffers(1, &m_IboId);
	// Material
	if (NULL != m_pMaterial)
	{
		m_pMaterial->delGLC_Geom(getID());	//Remove Geometry from the material usage collection
		if (m_pMaterial->isUnused()) delete m_pMaterial;
	}
}

/////////////////////////////////////////////////////////////////////
// Get Functions
//////////////////////////////////////////////////////////////////////

// return the geometry bounding box
GLC_BoundingBox* GLC_VboGeom::getBoundingBox(void) const
{
	return NULL;
}

/////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////

// Material
void GLC_VboGeom::setMaterial(GLC_Material* pMat)
{
	if (pMat != m_pMaterial)
	{
		if (pMat != NULL)
		{
			pMat->addGLC_Geom(this);
		}

		if (m_pMaterial != NULL)
		{
			m_pMaterial->delGLC_Geom(getID());
			if (m_pMaterial->isUnused()) delete m_pMaterial;
		}

		m_pMaterial= pMat;

		// Test if the material is transparent
		if (m_pMaterial->isTransparent())
		{
			setTransparency(true);
		}
	}
}

//////////////////////////////////////////////////////////////////////
// OpenGL Functions
//////////////////////////////////////////////////////////////////////

// if the geometry have a texture, load it
void GLC_VboGeom::glLoadTexture(void)
{
	m_pMaterial->glLoadTexture();
}

// Geometry display
void GLC_VboGeom::glExecute(bool isSelected, bool forceWire)
{
	// Define Geometry's property
	glPropGeom(isSelected, forceWire);

	if (0 == m_VboId)
	{
		createVBOs();
	}
	else
	{
		glBindBuffer(GL_ARRAY_BUFFER, m_VboId);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IboId);
	}

	glDraw();
	m_GeometryIsValid= true;

	// Unbind VBOs
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	// OpenGL error handler
	GLenum error= glGetError();
	if (error != GL_NO_ERROR)
	{
		GLC_OpenGlException OpenGlException("GLC_VboGeom::GlExecute ", error);
		throw(OpenGlException);
	}
}

// Virtual interface for OpenGL Geometry properties.
void GLC_VboGeom::glPropGeom(bool isSelected, bool forceWire)
{

	if(m_IsWire || forceWire)
	{
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		if (isSelected) GLC_SelectionMaterial::glExecute();
		else glColor4f(getdRed(), getdGreen(), getdBlue(), getdAlpha());			// is color
	}
	else if (m_pMaterial->getAddRgbaTexture())
	{
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_LIGHTING);
		m_pMaterial->glExecute();
		if (isSelected) GLC_SelectionMaterial::glExecute();
	}
	else
	{
		glDisable(GL_TEXTURE_2D);
		glEnable(GL_LIGHTING);
		if (isSelected) GLC_SelectionMaterial::glExecute();
		else m_pMaterial->glExecute();
	}

	// OpenGL error handler
	GLenum error= glGetError();
	if (error != GL_NO_ERROR)
	{
		GLC_OpenGlException OpenGlException("GLC_VboGeom::GlPropGeom ", error);
		throw(OpenGlException);
	}
}

// Vbo creation
void GLC_VboGeom::createVBOs()
{
	glGenBuffers(1, &m_VboId);
	glBindBuffer(GL_ARRAY_BUFFER, m_VboId);
	glGenBuffers(1, &m_IboId);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IboId);
}
<commit_msg>Force to use selection shader (Test purpose)<commit_after>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.0.0, packaged on August, 2008.

 http://glc-lib.sourceforge.net

 GLC-lib is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 GLC-lib is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/

//! \file glc_vbogeom.cpp Implementation of the GLC_VboGeom class.

#include "glc_vbogeom.h"
#include "glc_openglexception.h"
#include "glc_selectionmaterial.h"

//////////////////////////////////////////////////////////////////////
// Constructor destructor
//////////////////////////////////////////////////////////////////////
// Default constructor
GLC_VboGeom::GLC_VboGeom(const QString& name, const bool typeIsWire)
:GLC_Object(name)
, m_VboId(0)
, m_IboId(0)
, m_GeometryIsValid(false)	// By default geometry is invalid
, m_pMaterial(NULL)			// have to be set later in constructor
, m_UseColorPerVertex(false)
, m_IsWire(typeIsWire)		// the geometry type
, m_IsTransparent(false)	// Not transparent by default
{
	// Material is set here
	setMaterial(new GLC_Material());
}
// Copy constructor
GLC_VboGeom::GLC_VboGeom(const GLC_VboGeom& sourceGeom)
:GLC_Object(sourceGeom)
, m_VboId(0)
, m_IboId(0)
, m_GeometryIsValid(false)	// By default geometry is invalid
, m_pMaterial(NULL)			// have to be set later in constructor
, m_UseColorPerVertex(sourceGeom.m_UseColorPerVertex)
, m_IsWire(sourceGeom.m_IsWire)
, m_IsTransparent(sourceGeom.m_IsTransparent)
{
	m_Uid= glc::GLC_GenID();
	// Material is copy here
	setMaterial(new GLC_Material());
	m_pMaterial->setMaterial(sourceGeom.getMaterial());
}

GLC_VboGeom::~GLC_VboGeom()
{
	// VBO
	if (0 != m_VboId)
		glDeleteBuffers(1, &m_VboId);
	// IBO
	if (0 != m_IboId)
		glDeleteBuffers(1, &m_IboId);
	// Material
	if (NULL != m_pMaterial)
	{
		m_pMaterial->delGLC_Geom(getID());	//Remove Geometry from the material usage collection
		if (m_pMaterial->isUnused()) delete m_pMaterial;
	}
}

/////////////////////////////////////////////////////////////////////
// Get Functions
//////////////////////////////////////////////////////////////////////

// return the geometry bounding box
GLC_BoundingBox* GLC_VboGeom::getBoundingBox(void) const
{
	return NULL;
}

/////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////

// Material
void GLC_VboGeom::setMaterial(GLC_Material* pMat)
{
	if (pMat != m_pMaterial)
	{
		if (pMat != NULL)
		{
			pMat->addGLC_Geom(this);
		}

		if (m_pMaterial != NULL)
		{
			m_pMaterial->delGLC_Geom(getID());
			if (m_pMaterial->isUnused()) delete m_pMaterial;
		}

		m_pMaterial= pMat;

		// Test if the material is transparent
		if (m_pMaterial->isTransparent())
		{
			setTransparency(true);
		}
	}
}

//////////////////////////////////////////////////////////////////////
// OpenGL Functions
//////////////////////////////////////////////////////////////////////

// if the geometry have a texture, load it
void GLC_VboGeom::glLoadTexture(void)
{
	m_pMaterial->glLoadTexture();
}

// Geometry display
void GLC_VboGeom::glExecute(bool isSelected, bool forceWire)
{
	// Define Geometry's property
	glPropGeom(isSelected, forceWire);

	if (0 == m_VboId)
	{
		createVBOs();
	}
	else
	{
		glBindBuffer(GL_ARRAY_BUFFER, m_VboId);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IboId);
	}
	if (isSelected)
	{
		GLC_SelectionMaterial::useShader();
	}

	glDraw();
	if (isSelected) GLC_SelectionMaterial::unUseShader();
	m_GeometryIsValid= true;

	// Unbind VBOs
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	// OpenGL error handler
	GLenum error= glGetError();
	if (error != GL_NO_ERROR)
	{
		GLC_OpenGlException OpenGlException("GLC_VboGeom::GlExecute ", error);
		throw(OpenGlException);
	}
}

// Virtual interface for OpenGL Geometry properties.
void GLC_VboGeom::glPropGeom(bool isSelected, bool forceWire)
{

	if(m_IsWire || forceWire)
	{
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		if (isSelected) GLC_SelectionMaterial::glExecute();
		else glColor4f(getdRed(), getdGreen(), getdBlue(), getdAlpha());			// is color
	}
	else if (m_pMaterial->getAddRgbaTexture())
	{
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_LIGHTING);
		m_pMaterial->glExecute();
		if (isSelected) GLC_SelectionMaterial::glExecute();
	}
	else
	{
		glDisable(GL_TEXTURE_2D);
		glEnable(GL_LIGHTING);
		if (isSelected) GLC_SelectionMaterial::glExecute();
		else m_pMaterial->glExecute();
	}

	// OpenGL error handler
	GLenum error= glGetError();
	if (error != GL_NO_ERROR)
	{
		GLC_OpenGlException OpenGlException("GLC_VboGeom::GlPropGeom ", error);
		throw(OpenGlException);
	}
}

// Vbo creation
void GLC_VboGeom::createVBOs()
{
	glGenBuffers(1, &m_VboId);
	glBindBuffer(GL_ARRAY_BUFFER, m_VboId);
	glGenBuffers(1, &m_IboId);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IboId);
}
<|endoftext|>


<commit_before>#ifndef __MODEL_HPP_INCLUDED
#define __MODEL_HPP_INCLUDED

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h>
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp>
#endif

#include <iostream>
#include <queue> // std::queue
#include <string.h>
#include "globals.hpp"
#include "shader.hpp"
#include "heightmap_loader.hpp"
#include "objloader.hpp"

namespace model
{
    class World
    {
        public:
            // constructor.
            World();

            // destructor.
            ~World();

            // this method renders the entire world, one shader at a time.
            void render();

            // this method sets a shader pointer.
            void set_pointer(GLuint shaderID, void* shader_pointer);

            // this method gets a shader pointer.
            void* get_pointer(GLuint shaderID);

            // this method gets a shader ID and removes it from the `free_shaderID_queue` if it was popped from the queue.
            GLuint get_shaderID();

        private:
            std::vector<void*> shader_pointer_vector;
            std::queue<GLuint> free_shaderID_queue;
    };

    class Shader
    {
        public:
            // constructor.
            Shader(ShaderStruct shader_struct);

            // destructor.
            ~Shader();

            // this method renders all species using this shader.
            void render();

            // this method sets a species pointer.
            void set_pointer(GLuint speciesID, void* species_pointer);

            // this method gets a species pointer.
            void* get_pointer(GLuint speciesID);

            // this method gets a species ID and removes it from the `free_speciesID_queue` if it was popped from the queue.
            GLuint get_speciesID();

            // this method sets pointer to this shader to NULL, sets `world_pointer` according to the input, and requests a new `shaderID` from the new world.
            void switch_to_new_world(model::World *new_world_pointer);

            model::World *world_pointer;          // pointer to the world.

            GLuint shaderID;                      // shader ID, returned by `model::World->get_shaderID()`.

            std::string vertex_shader;            // filename of vertex shader.
            std::string fragment_shader;          // filename of fragment shader.

            GLuint programID;                     // shaders' programID, returned by `LoadShaders`.

        private:
            std::vector<void*> species_pointer_vector;
            std::queue<GLuint> free_speciesID_queue;

            const char *char_vertex_shader;
            const char *char_fragment_shader;
    };

    class Graph
    {
        public:
            // constructor.
            Graph();

            // destructor.
            ~Graph();

            // this method sets a node pointer.
            void set_pointer(GLuint nodeID, void* node_pointer);

            // this method gets a node pointer.
            void* get_pointer(GLuint nodeID);

            // this method gets a node ID and removes it from the `free_nodeID_queue` if it was popped from the queue.
            GLuint get_nodeID();

        private:
            std::vector<void*> node_pointer_vector;
            std::queue<GLuint> free_nodeID_queue;
    };

    // `Node` is not a subclass of `Graph` because if the graph splits, node may be transferred to an another graph.
    // Transferring a node to a new graph naturally requires appropriate reindexing of `nodeID`s.
    // The graph in which a node belongs is accessible through `void* graph_pointer` (must be cast to `model::Graph*`).
    class Node
    {
        public:
            // constructor.
            Node(NodeStruct node_struct);

            // destructor.
            ~Node();

            // this method creates a bidirectional link.
            // creating of bidirectional links is not possible before all nodes are created.
            void create_bidirectional_link(GLuint nodeID);

            // this method deletes a bidirectional link.
            // deleting of links is not possible before all nodes are created.
            void delete_bidirectional_link(GLuint nodeID);

            // this method transfers this node to a new graph.
            // links will not be changed.
            // all nodes that are to be transferred must be transferred separately.
            // before transfering any node to a new graph,
            // all links to nodes that do not belong to the new graph of this node must be deleted with separate `delete_bidirectional_link` calls.
            void transfer_to_new_graph(model::Graph *new_graph_pointer);

            GLuint nodeID;
            model::Graph *graph_pointer;

            // nodes do not keep pointers to neighbor nodes, because all pointer values are not known yet before all nodes are created.
            std::vector<GLuint> neighbor_nodeIDs;

        private:
            // this method creates an unidirectional link.
            // in the constructor only unidirectional links can be created.
            void create_unidirectional_link(GLuint nodeID);

            // this method deletes an unidirectional link.
            void delete_unidirectional_link(GLuint nodeID);

            glm::vec3 coordinate_vector;
    };

    class Species
    {
        public:
            // constructor.
            Species(SpeciesStruct species_struct);

            // destructor.
            ~Species();

            // this method renders all objects of this species.
            void render();

            // this method sets a object pointer.
            void set_pointer(GLuint objectID, void* object_pointer);

            // this method gets a object pointer.
            void* get_pointer(GLuint objectID);

            // this method gets a object ID and removes it from the `free_objectID_queue` if it was popped from the queue.
            GLuint get_objectID();

            // this method sets pointer to this species to NULL, sets `shader_pointer` according to the input, and requests a new `speciesID` from the new shader.
            void switch_to_new_shader(model::Shader *new_shader_pointer);

            model::Shader *shader_pointer;           // pointer to the shader.

            std::string model_file_format;           // type of the model file, eg. `"bmp"`.
            std::string model_filename;              // filename of the model file.
            std::string texture_file_format;         // type of the model file, eg. `"bmp"`.
            std::string texture_filename;            // filename of the model file.
            std::string color_channel;               // filename of fragment shader.
            std::vector<ObjectStruct> object_vector; // vector of individual objects of this species.
            glm::vec3 lightPos;                      // light position.

            void *vertex_UV_pointer;                 // pointer to the vertex & UV species (not yet in use!).
            void *texture_pointer;                   // pointer to the texture species (not yet in use!).

            // The rest fields are created in the constructor.
            GLuint speciesID;                      // species ID, returned by `model::World->get_speciesID()`.
            GLuint lightID;                        // light ID, returned by `glGetUniformLocation(programID, "LightPosition_worldspace");`.
            GLuint texture;                        // Texture, returned by `load_DDS_texture` or `load_BMP_texture`.
            GLuint textureID;                      // texture ID, returned by `glGetUniformLocation(programID, "myTextureSampler");`.
            GLuint MatrixID;
            GLuint ViewMatrixID;
            GLuint ModelMatrixID;
            GLuint vertexPosition_modelspaceID;
            GLuint vertexUVID;
            GLuint vertexNormal_modelspaceID;

            std::vector<glm::vec3> vertices;       // vertices of the object.
            std::vector<glm::vec2> UVs;            // UVs of the object.
            std::vector<glm::vec3> normals;        // normals of the object.

            std::vector<GLuint> indices;           // the deleted vertices will be reused (though it is not required, if there's enough memory).
            std::vector<glm::vec3> indexed_vertices;
            std::vector<glm::vec2> indexed_UVs;
            std::vector<glm::vec3> indexed_normals;

            GLuint vertexbuffer;
            GLuint uvbuffer;
            GLuint normalbuffer;
            GLuint elementbuffer;

            glm::mat4 ProjectionMatrix;
            glm::mat4 ViewMatrix;
        private:
            const char *char_model_file_format;
            const char *char_model_filename;
            const char *char_texture_file_format;
            const char *char_texture_filename;
            const char *char_color_channel;

            std::vector<void*> object_pointer_vector;
            std::queue<GLuint> free_objectID_queue;
    };

    class Object
    {
        public:
            // constructor.
            Object(ObjectStruct object_struct);

            // destructor.
            ~Object();

            // this method renders this object.
            void render();

            // this method sets pointer to this object to NULL, sets `species_pointer` according to the input, and requests a new `objectID` from the new species.
            void switch_to_new_species(model::Species *new_species_pointer);

            model::Species *species_pointer;       // pointer to the species.

            GLuint objectID;                      // object ID, returned by `model::Species->get_objectID()`.

            bool has_entered;
            glm::vec3 coordinate_vector;           // rotate vector.
            GLfloat rotate_angle;                  // rotate angle.
            glm::vec3 rotate_vector;               // rotate vector.
            glm::vec3 translate_vector;            // translate vector.

            // The rest fields are created in the constructor.
            glm::mat4 model_matrix;                // model matrix.
            std::vector<glm::vec3> vertices;       // vertices of the object.
            std::vector<glm::vec2> UVs;            // UVs of the object.
            std::vector<glm::vec3> normals;        // normals of the object. not used at the moment.

            glm::mat4 MVP_matrix;                  // model view projection matrix.
    };
}

#endif
<commit_msg>`class Species`: `GLuint speciesID` on `private`-muuttuja.<commit_after>#ifndef __MODEL_HPP_INCLUDED
#define __MODEL_HPP_INCLUDED

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h>
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp>
#endif

#include <iostream>
#include <queue> // std::queue
#include <string.h>
#include "globals.hpp"
#include "shader.hpp"
#include "heightmap_loader.hpp"
#include "objloader.hpp"

namespace model
{
    class World
    {
        public:
            // constructor.
            World();

            // destructor.
            ~World();

            // this method renders the entire world, one shader at a time.
            void render();

            // this method sets a shader pointer.
            void set_pointer(GLuint shaderID, void* shader_pointer);

            // this method gets a shader pointer.
            void* get_pointer(GLuint shaderID);

            // this method gets a shader ID and removes it from the `free_shaderID_queue` if it was popped from the queue.
            GLuint get_shaderID();

        private:
            std::vector<void*> shader_pointer_vector;
            std::queue<GLuint> free_shaderID_queue;
    };

    class Shader
    {
        public:
            // constructor.
            Shader(ShaderStruct shader_struct);

            // destructor.
            ~Shader();

            // this method renders all species using this shader.
            void render();

            // this method sets a species pointer.
            void set_pointer(GLuint speciesID, void* species_pointer);

            // this method gets a species pointer.
            void* get_pointer(GLuint speciesID);

            // this method gets a species ID and removes it from the `free_speciesID_queue` if it was popped from the queue.
            GLuint get_speciesID();

            // this method sets pointer to this shader to NULL, sets `world_pointer` according to the input, and requests a new `shaderID` from the new world.
            void switch_to_new_world(model::World *new_world_pointer);

            model::World *world_pointer;          // pointer to the world.

            GLuint shaderID;                      // shader ID, returned by `model::World->get_shaderID()`.

            std::string vertex_shader;            // filename of vertex shader.
            std::string fragment_shader;          // filename of fragment shader.

            GLuint programID;                     // shaders' programID, returned by `LoadShaders`.

        private:
            std::vector<void*> species_pointer_vector;
            std::queue<GLuint> free_speciesID_queue;

            const char *char_vertex_shader;
            const char *char_fragment_shader;
    };

    class Graph
    {
        public:
            // constructor.
            Graph();

            // destructor.
            ~Graph();

            // this method sets a node pointer.
            void set_pointer(GLuint nodeID, void* node_pointer);

            // this method gets a node pointer.
            void* get_pointer(GLuint nodeID);

            // this method gets a node ID and removes it from the `free_nodeID_queue` if it was popped from the queue.
            GLuint get_nodeID();

        private:
            std::vector<void*> node_pointer_vector;
            std::queue<GLuint> free_nodeID_queue;
    };

    // `Node` is not a subclass of `Graph` because if the graph splits, node may be transferred to an another graph.
    // Transferring a node to a new graph naturally requires appropriate reindexing of `nodeID`s.
    // The graph in which a node belongs is accessible through `void* graph_pointer` (must be cast to `model::Graph*`).
    class Node
    {
        public:
            // constructor.
            Node(NodeStruct node_struct);

            // destructor.
            ~Node();

            // this method creates a bidirectional link.
            // creating of bidirectional links is not possible before all nodes are created.
            void create_bidirectional_link(GLuint nodeID);

            // this method deletes a bidirectional link.
            // deleting of links is not possible before all nodes are created.
            void delete_bidirectional_link(GLuint nodeID);

            // this method transfers this node to a new graph.
            // links will not be changed.
            // all nodes that are to be transferred must be transferred separately.
            // before transfering any node to a new graph,
            // all links to nodes that do not belong to the new graph of this node must be deleted with separate `delete_bidirectional_link` calls.
            void transfer_to_new_graph(model::Graph *new_graph_pointer);

            GLuint nodeID;
            model::Graph *graph_pointer;

            // nodes do not keep pointers to neighbor nodes, because all pointer values are not known yet before all nodes are created.
            std::vector<GLuint> neighbor_nodeIDs;

        private:
            // this method creates an unidirectional link.
            // in the constructor only unidirectional links can be created.
            void create_unidirectional_link(GLuint nodeID);

            // this method deletes an unidirectional link.
            void delete_unidirectional_link(GLuint nodeID);

            glm::vec3 coordinate_vector;
    };

    class Species
    {
        public:
            // constructor.
            Species(SpeciesStruct species_struct);

            // destructor.
            ~Species();

            // this method renders all objects of this species.
            void render();

            // this method sets a object pointer.
            void set_pointer(GLuint objectID, void* object_pointer);

            // this method gets a object pointer.
            void* get_pointer(GLuint objectID);

            // this method gets a object ID and removes it from the `free_objectID_queue` if it was popped from the queue.
            GLuint get_objectID();

            // this method sets pointer to this species to NULL, sets `shader_pointer` according to the input, and requests a new `speciesID` from the new shader.
            void switch_to_new_shader(model::Shader *new_shader_pointer);

            model::Shader *shader_pointer;           // pointer to the shader.

            std::string model_file_format;           // type of the model file, eg. `"bmp"`.
            std::string model_filename;              // filename of the model file.
            std::string texture_file_format;         // type of the model file, eg. `"bmp"`.
            std::string texture_filename;            // filename of the model file.
            std::string color_channel;               // filename of fragment shader.
            std::vector<ObjectStruct> object_vector; // vector of individual objects of this species.
            glm::vec3 lightPos;                      // light position.

            void *vertex_UV_pointer;                 // pointer to the vertex & UV species (not yet in use!).
            void *texture_pointer;                   // pointer to the texture species (not yet in use!).

            // The rest fields are created in the constructor.
            GLuint lightID;                        // light ID, returned by `glGetUniformLocation(programID, "LightPosition_worldspace");`.
            GLuint texture;                        // Texture, returned by `load_DDS_texture` or `load_BMP_texture`.
            GLuint textureID;                      // texture ID, returned by `glGetUniformLocation(programID, "myTextureSampler");`.
            GLuint MatrixID;
            GLuint ViewMatrixID;
            GLuint ModelMatrixID;
            GLuint vertexPosition_modelspaceID;
            GLuint vertexUVID;
            GLuint vertexNormal_modelspaceID;

            std::vector<glm::vec3> vertices;       // vertices of the object.
            std::vector<glm::vec2> UVs;            // UVs of the object.
            std::vector<glm::vec3> normals;        // normals of the object.

            std::vector<GLuint> indices;           // the deleted vertices will be reused (though it is not required, if there's enough memory).
            std::vector<glm::vec3> indexed_vertices;
            std::vector<glm::vec2> indexed_UVs;
            std::vector<glm::vec3> indexed_normals;

            GLuint vertexbuffer;
            GLuint uvbuffer;
            GLuint normalbuffer;
            GLuint elementbuffer;

            glm::mat4 ProjectionMatrix;
            glm::mat4 ViewMatrix;
        private:
            GLuint speciesID;                      // species ID, returned by `model::World->get_speciesID()`.
            const char *char_model_file_format;
            const char *char_model_filename;
            const char *char_texture_file_format;
            const char *char_texture_filename;
            const char *char_color_channel;

            std::vector<void*> object_pointer_vector;
            std::queue<GLuint> free_objectID_queue;
    };

    class Object
    {
        public:
            // constructor.
            Object(ObjectStruct object_struct);

            // destructor.
            ~Object();

            // this method renders this object.
            void render();

            // this method sets pointer to this object to NULL, sets `species_pointer` according to the input, and requests a new `objectID` from the new species.
            void switch_to_new_species(model::Species *new_species_pointer);

            model::Species *species_pointer;       // pointer to the species.

            GLuint objectID;                      // object ID, returned by `model::Species->get_objectID()`.

            bool has_entered;
            glm::vec3 coordinate_vector;           // rotate vector.
            GLfloat rotate_angle;                  // rotate angle.
            glm::vec3 rotate_vector;               // rotate vector.
            glm::vec3 translate_vector;            // translate vector.

            // The rest fields are created in the constructor.
            glm::mat4 model_matrix;                // model matrix.
            std::vector<glm::vec3> vertices;       // vertices of the object.
            std::vector<glm::vec2> UVs;            // UVs of the object.
            std::vector<glm::vec3> normals;        // normals of the object. not used at the moment.

            glm::mat4 MVP_matrix;                  // model view projection matrix.
    };
}

#endif
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Ruben Van Boxem
 *
 * 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.
 **/

/*
 * Signal
 * Registers observers.
 * Notifies registered observers.
 */

#ifndef SKUI_CORE_SIGNAL_H
#define SKUI_CORE_SIGNAL_H

#include "core/slot.h++"
#include "core/trackable.h++"
#include "core/value_ptr.h++"

#include <algorithm>
#include <functional>
#include <iterator>
#include <list>
#include <memory>
#include <mutex>
#include <utility>

namespace skui
{
  namespace core
  {
    namespace implementation
    {
      template<typename... ArgTypes>
      class signal_base : public tracker
      {
      public:
        using function_type = void(*)(ArgTypes...);
        using slot_type = slot<void, ArgTypes...>;
        using object_slot_type = std::pair<const trackable*, value_ptr<slot_type>>;
        using connection_type = typename std::list<object_slot_type>::const_iterator;

        signal_base() = default;
        ~signal_base() { disconnect_all(); }

        signal_base(const signal_base& other)
          : slots(other.slots.begin(), other.slots.end())
        {}

        signal_base(signal_base&& other) : slots(std::move(other.slots)) {}
        signal_base& operator=(signal_base other) { swap(slots, other.slots); return *this; }

        virtual void trackable_deleted(const trackable* tracker) override
        {
          disconnect(tracker);
        }

        virtual void trackable_moved(const trackable* old_object, const trackable* new_object) override
        {
          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);
          std::for_each(slots.begin(), slots.end(),
                        [&old_object, &new_object](object_slot_type& object_slot)
                        {
                          if(object_slot.first == old_object)
                            object_slot.first = new_object;
                        });
        }

        virtual void trackable_copied(const trackable* old_object, const trackable* new_object) override
        {
          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);
          std::for_each(slots.begin(), slots.end(),
                        [&old_object, &new_object, this](const object_slot_type& object_slot)
                        {
                          if(object_slot.first == old_object)
                            slots.push_back({new_object, object_slot.second});
                        });

        }

        template<typename Callable, typename ReturnType = void>
        connection_type connect(Callable&& callable)
        {
          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);
          slots.emplace_back(nullptr, make_value<function_slot<Callable, ReturnType, ArgTypes...>>(callable));
          return --slots.end();
        }

        template<typename Class, typename ReturnType>
        connection_type connect(Class* object, ReturnType(Class::* slot)(ArgTypes...))
        {
          static_assert(std::is_base_of<trackable, Class>::value,
                        "You can only connect to member functions of a trackable object.");

          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);

          slots.emplace_back(object, make_value<member_function_slot<Class, ReturnType(Class::*)(ArgTypes...), ReturnType, ArgTypes...>>(slot));
          object->track(this);

          return --slots.end();
        }

        template<typename Class, typename ReturnType>
        connection_type connect(const Class* object, ReturnType(Class::* slot)(ArgTypes...) const)
        {
          static_assert(std::is_base_of<trackable, Class>::value,
                        "You can only connect to member functions of a trackable object");
          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);

          object_slot_type object_slot(object, make_value<const_member_function_slot<Class, ReturnType(Class::*)(ArgTypes...) const, ReturnType, ArgTypes...>>(slot));
          slots.emplace_back(std::move(object_slot));
          object->track(this);

          return --slots.end();
        }

        // connects first object like first object
        void connect(trackable* /*first*/, trackable* /*second*/)
        {
          // trackable copy constructor makes second->track(this) unnecessary
          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);
        }

        // removes a previously made connection, handles lifetime tracking if it was the last connection to a specific object
        void disconnect(connection_type connection)
        {
          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);
          const trackable* object = connection->first;

          slots.erase(connection);
          if(object && std::any_of(slots.begin(), slots.end(),
                                   [&object](const object_slot_type& object_slot)
                                   { return object_slot.first == object; }))
            object->untrack(this);
        }

        // removes all connections to an object
        void disconnect(const trackable* object)
        {
          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);
          object->untrack(this);
          slots.remove_if([object](const object_slot_type& object_slot)
                          {
                            return object == object_slot.first;
                          });
        }

        // removes all connections
        void disconnect_all()
        {
          const std::lock_guard<decltype(slots_mutex)> lock(slots_mutex);
          for(object_slot_type& object_slot : slots)
          {
            auto trackable = object_slot.first;
            if(trackable)
              trackable->untrack(this);
          }
          slots.clear();
        }

      protected:
        // mutable here allows to connect to a const object's signals
        mutable std::list<object_slot_type> slots;
        mutable std::mutex slots_mutex;
      };
    }

    template<typename... ArgTypes>
    class signal : public implementation::signal_base<ArgTypes...>
    {
    public:
      signal() = default;

      void emit(ArgTypes... arguments) const
      {
        std::lock_guard<decltype(this->slots_mutex)> lock(this->slots_mutex);
        for(auto&& object_slot : this->slots)
        {
          (*object_slot.second)(object_slot.first, arguments...);
        }
      }
    };

    // Parameterless specialization
    template<> class signal<> : public implementation::signal_base<>
    {
    public:
      signal() = default;

      void emit() const
      {
        std::lock_guard<decltype(this->slots_mutex)> lock(this->slots_mutex);
        for(auto&& object_slot : this->slots)
        {
          (*object_slot.second)(object_slot.first);
        }
      }
    };
  }
}

#endif
<commit_msg>Clean up core::signal code a bit.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Ruben Van Boxem
 *
 * 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.
 **/

/*
 * Signal
 * Registers observers.
 * Notifies registered observers.
 */

#ifndef SKUI_CORE_SIGNAL_H
#define SKUI_CORE_SIGNAL_H

#include "core/slot.h++"
#include "core/trackable.h++"
#include "core/value_ptr.h++"

#include <algorithm>
#include <functional>
#include <iterator>
#include <list>
#include <memory>
#include <mutex>
#include <utility>

namespace skui
{
  namespace core
  {
    namespace implementation
    {
      template<typename... ArgTypes>
      class signal_base : public tracker
      {
        using mutex_type = std::mutex;
        using mutex_lock = const std::lock_guard<mutex_type>;

      public:
        using function_type = void(*)(ArgTypes...);
        using slot_type = slot<void, ArgTypes...>;
        using object_slot_type = std::pair<const trackable*, value_ptr<slot_type>>;
        using connection_type = typename std::list<object_slot_type>::const_iterator;

        signal_base() = default;
        ~signal_base() override { disconnect_all(); }

        signal_base(const signal_base& other)
          : slots(other.slots.begin(), other.slots.end())
        {}

        signal_base(signal_base&& other) : slots(std::move(other.slots)) {}
        signal_base& operator=(signal_base other) { swap(slots, other.slots); return *this; }

        virtual void trackable_deleted(const trackable* tracker) override
        {
          disconnect(tracker);
        }

        virtual void trackable_moved(const trackable* old_object, const trackable* new_object) override
        {
          mutex_lock lock(slots_mutex);
          for(auto& object_slot : slots)
          {
            if(object_slot.first == old_object)
              object_slot.first = new_object;
          }
        }

        virtual void trackable_copied(const trackable* old_object, const trackable* new_object) override
        {
          mutex_lock lock(slots_mutex);
          for(const auto& object_slot : slots)
          {
            if(object_slot.first == old_object)
              slots.emplace_back(new_object, object_slot.second);
          }
        }

        template<typename Callable, typename ReturnType = void>
        connection_type connect(Callable&& callable)
        {
          mutex_lock lock(slots_mutex);
          slots.emplace_back(nullptr, make_value<callable_slot<Callable, ReturnType, ArgTypes...>>(callable));
          return --slots.end();
        }

        template<typename Class, typename ReturnType>
        connection_type connect(Class* object, ReturnType(Class::* slot)(ArgTypes...))
        {
          static_assert(std::is_base_of<trackable, Class>::value,
                        "You can only connect to member functions of a trackable object.");

          mutex_lock lock(slots_mutex);

          slots.emplace_back(object, make_value<member_function_slot<Class, ReturnType(Class::*)(ArgTypes...), ReturnType, ArgTypes...>>(slot));
          object->track(this);

          return --slots.end();
        }

        template<typename Class, typename ReturnType>
        connection_type connect(const Class* object, ReturnType(Class::* slot)(ArgTypes...) const)
        {
          static_assert(std::is_base_of<trackable, Class>::value,
                        "You can only connect to member functions of a trackable object");

          mutex_lock lock(slots_mutex);

          slots.emplace_back(object, make_value<const_member_function_slot<Class, ReturnType(Class::*)(ArgTypes...) const, ReturnType, ArgTypes...>>(slot));
          object->track(this);

          return --slots.end();
        }

        // connects first object like second object
        connection_type connect(trackable* /*first*/, trackable* /*second*/)
        {
          // trackable copy constructor makes second->track(this) unnecessary
          mutex_lock lock(slots_mutex);
        }

        // removes a previously made connection, handles lifetime tracking if it was the last connection to a specific object
        void disconnect(connection_type connection)
        {
          mutex_lock lock(slots_mutex);
          const trackable* object = connection->first;

          slots.erase(connection);
          if(object && std::any_of(slots.begin(), slots.end(),
                                   [&object](const object_slot_type& object_slot)
                                   { return object_slot.first == object; }))
            object->untrack(this);
        }

        // removes all connections to an object
        void disconnect(const trackable* object)
        {
          mutex_lock lock(slots_mutex);
          object->untrack(this);
          slots.remove_if([object](const object_slot_type& object_slot)
                          {
                            return object == object_slot.first;
                          });
        }

        // removes all connections
        void disconnect_all()
        {
          mutex_lock lock(slots_mutex);
          for(object_slot_type& object_slot : slots)
          {
            auto trackable = object_slot.first;
            if(trackable)
              trackable->untrack(this);
          }
          slots.clear();
        }

      protected:
        // mutable here allows to connect to a const object's signals
        mutable std::list<object_slot_type> slots;
        mutable mutex_type slots_mutex;
      };
    }

    template<typename... ArgTypes>
    class signal : public implementation::signal_base<ArgTypes...>
    {
    public:
      signal() = default;

      void emit(ArgTypes... arguments) const
      {
        std::lock_guard<decltype(this->slots_mutex)> lock(this->slots_mutex);
        for(auto&& object_slot : this->slots)
        {
          (*object_slot.second)(object_slot.first, arguments...);
        }
      }
    };

    // Parameterless specialization
    template<> class signal<> : public implementation::signal_base<>
    {
    public:
      signal() = default;

      void emit() const
      {
        std::lock_guard<decltype(this->slots_mutex)> lock(this->slots_mutex);
        for(auto&& object_slot : this->slots)
        {
          (*object_slot.second)(object_slot.first);
        }
      }
    };
  }
}

#endif
<|endoftext|>


<commit_before>// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Skeleton.hpp>
#include <Nazara/Utility/AxisAlignedBox.hpp>
#include <map>
#include <Nazara/Utility/Debug.hpp>

struct NzSkeletonImpl
{
	std::map<NzString, unsigned int> jointMap;
	std::vector<NzJoint> joints;
	NzAxisAlignedBox aabb;
	bool jointMapUpdated = false;
};

NzSkeleton::NzSkeleton(const NzSkeleton& skeleton)
{
	if (skeleton.m_impl)
	{
		m_impl = new NzSkeletonImpl;
		m_impl->jointMap = skeleton.m_impl->jointMap;
		m_impl->jointMapUpdated = skeleton.m_impl->jointMapUpdated;
		m_impl->joints = skeleton.m_impl->joints;
	}
	else
		m_impl = nullptr;
}

NzSkeleton::~NzSkeleton()
{
	Destroy();
}

bool NzSkeleton::Create(unsigned int jointCount)
{
	#if NAZARA_UTILITY_SAFE
	if (jointCount == 0)
	{
		NazaraError("Joint count must be over 0");
		return false;
	}
	#endif

	m_impl = new NzSkeletonImpl;
	m_impl->joints.resize(jointCount, NzJoint(this));

	return true;
}

void NzSkeleton::Destroy()
{
	if (m_impl)
	{
		delete m_impl;
		m_impl = nullptr;
	}
}

const NzAxisAlignedBox& NzSkeleton::GetAABB() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return NzAxisAlignedBox::Null;
	}
	#endif

	if (m_impl->aabb.IsNull())
	{
		for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
			m_impl->aabb.ExtendTo(m_impl->joints[i].GetDerivedTranslation());
	}

	return m_impl->aabb;
}

NzJoint* NzSkeleton::GetJoint(const NzString& jointName)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}
	#endif

	if (!m_impl->jointMapUpdated)
		UpdateJointMap();

	auto it = m_impl->jointMap.find(jointName);

	#if NAZARA_UTILITY_SAFE
	if (it == m_impl->jointMap.end())
	{
		NazaraError("Joint not found");
		return nullptr;
	}
	#endif

	// Invalidation de l'AABB
	m_impl->aabb.SetNull();

	return &m_impl->joints[it->second];
}

NzJoint* NzSkeleton::GetJoint(unsigned int index)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}

	if (index >= m_impl->joints.size())
	{
		NazaraError("Joint index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
		return nullptr;
	}
	#endif

	// Invalidation de l'AABB
	m_impl->aabb.SetNull();

	return &m_impl->joints[index];
}

const NzJoint* NzSkeleton::GetJoint(const NzString& jointName) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}
	#endif

	if (!m_impl->jointMapUpdated)
		UpdateJointMap();

	auto it = m_impl->jointMap.find(jointName);

	#if NAZARA_UTILITY_SAFE
	if (it == m_impl->jointMap.end())
	{
		NazaraError("Joint not found");
		return nullptr;
	}
	#endif

	return &m_impl->joints[it->second];
}

const NzJoint* NzSkeleton::GetJoint(unsigned int index) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}

	if (index >= m_impl->joints.size())
	{
		NazaraError("Joint index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
		return nullptr;
	}
	#endif

	return &m_impl->joints[index];
}

NzJoint* NzSkeleton::GetJoints()
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}
	#endif

	return &m_impl->joints[0];
}

const NzJoint* NzSkeleton::GetJoints() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}
	#endif

	return &m_impl->joints[0];
}

unsigned int NzSkeleton::GetJointCount() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return 0;
	}
	#endif

	return m_impl->joints.size();
}

int NzSkeleton::GetJointIndex(const NzString& jointName) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return -1;
	}
	#endif

	if (!m_impl->jointMapUpdated)
		UpdateJointMap();

	auto it = m_impl->jointMap.find(jointName);

	#if NAZARA_UTILITY_SAFE
	if (it == m_impl->jointMap.end())
	{
		NazaraError("Joint not found");
		return -1;
	}
	#endif

	return it->second;
}

void NzSkeleton::Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return;
	}

	if (!skeletonA.IsValid())
	{
		NazaraError("Skeleton A is invalid");
		return;
	}

	if (!skeletonB.IsValid())
	{
		NazaraError("Skeleton B is invalid");
		return;
	}

	if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount())
	{
		NazaraError("Skeletons must have the same joint count");
		return;
	}
	#endif

	NzJoint* jointsA = &skeletonA.m_impl->joints[0];
	NzJoint* jointsB = &skeletonB.m_impl->joints[0];
	for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
		m_impl->joints[i].Interpolate(jointsA[i], jointsB[i], interpolation);
}

void NzSkeleton::Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation, unsigned int* indices, unsigned int indiceCount)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return;
	}

	if (!skeletonA.IsValid())
	{
		NazaraError("Skeleton A is invalid");
		return;
	}

	if (!skeletonB.IsValid())
	{
		NazaraError("Skeleton B is invalid");
		return;
	}

	if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount())
	{
		NazaraError("Skeletons must have the same joint count");
		return;
	}
	#endif

	NzJoint* jointsA = &skeletonA.m_impl->joints[0];
	NzJoint* jointsB = &skeletonB.m_impl->joints[0];
	for (unsigned int i = 0; i < indiceCount; ++i)
	{
		unsigned int index = indices[i];

		#if NAZARA_UTILITY_SAFE
		if (index >= m_impl->joints.size())
		{
			NazaraError("Index #" + NzString::Number(i) + " out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
			return;
		}
		#endif

		m_impl->joints[index].Interpolate(jointsA[index], jointsB[index], interpolation);
	}
}

bool NzSkeleton::IsValid() const
{
	return m_impl != nullptr;
}

NzSkeleton& NzSkeleton::operator=(const NzSkeleton& skeleton)
{
	Destroy();

	if (skeleton.m_impl)
	{
		m_impl = new NzSkeletonImpl;
		m_impl->jointMap = skeleton.m_impl->jointMap;
		m_impl->jointMapUpdated = skeleton.m_impl->jointMapUpdated;
		m_impl->joints = skeleton.m_impl->joints;
	}

	return *this;
}

void NzSkeleton::InvalidateJointMap()
{
	#ifdef NAZARA_DEBUG
	if (!m_impl)
	{
		NazaraError("Invalid skeleton");
		return;
	}
	#endif

	m_impl->jointMapUpdated = false;
}

void NzSkeleton::UpdateJointMap() const
{
	#ifdef NAZARA_DEBUG
	if (!m_impl)
	{
		NazaraError("Invalid skeleton");
		return;
	}
	#endif

	m_impl->jointMap.clear();
	for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
	{
		NzString name = m_impl->joints[i].GetName();
		if (!name.IsEmpty())
		{
			#if NAZARA_UTILITY_SAFE
			auto it = m_impl->jointMap.find(name);
			if (it != m_impl->jointMap.end())
			{
				NazaraWarning("Joint name \"" + name + "\" is already present in joint map for joint #" + NzString::Number(it->second));
				continue;
			}
			#endif

			m_impl->jointMap[name] = i;
		}
	}

	m_impl->jointMapUpdated = true;
}
<commit_msg>Fixed copying a skeleton not copying hierarchy<commit_after>// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Skeleton.hpp>
#include <Nazara/Utility/AxisAlignedBox.hpp>
#include <map>
#include <Nazara/Utility/Debug.hpp>

struct NzSkeletonImpl
{
	std::map<NzString, unsigned int> jointMap;
	std::vector<NzJoint> joints;
	NzAxisAlignedBox aabb;
	bool jointMapUpdated = false;
};

NzSkeleton::NzSkeleton(const NzSkeleton& skeleton) :
m_impl(nullptr)
{
	operator=(skeleton);
}

NzSkeleton::~NzSkeleton()
{
	Destroy();
}

bool NzSkeleton::Create(unsigned int jointCount)
{
	#if NAZARA_UTILITY_SAFE
	if (jointCount == 0)
	{
		NazaraError("Joint count must be over 0");
		return false;
	}
	#endif

	m_impl = new NzSkeletonImpl;
	m_impl->joints.resize(jointCount, NzJoint(this));

	return true;
}

void NzSkeleton::Destroy()
{
	if (m_impl)
	{
		delete m_impl;
		m_impl = nullptr;
	}
}

const NzAxisAlignedBox& NzSkeleton::GetAABB() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return NzAxisAlignedBox::Null;
	}
	#endif

	if (m_impl->aabb.IsNull())
	{
		for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
			m_impl->aabb.ExtendTo(m_impl->joints[i].GetDerivedTranslation());
	}

	return m_impl->aabb;
}

NzJoint* NzSkeleton::GetJoint(const NzString& jointName)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}
	#endif

	if (!m_impl->jointMapUpdated)
		UpdateJointMap();

	auto it = m_impl->jointMap.find(jointName);

	#if NAZARA_UTILITY_SAFE
	if (it == m_impl->jointMap.end())
	{
		NazaraError("Joint not found");
		return nullptr;
	}
	#endif

	// Invalidation de l'AABB
	m_impl->aabb.SetNull();

	return &m_impl->joints[it->second];
}

NzJoint* NzSkeleton::GetJoint(unsigned int index)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}

	if (index >= m_impl->joints.size())
	{
		NazaraError("Joint index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
		return nullptr;
	}
	#endif

	// Invalidation de l'AABB
	m_impl->aabb.SetNull();

	return &m_impl->joints[index];
}

const NzJoint* NzSkeleton::GetJoint(const NzString& jointName) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}
	#endif

	if (!m_impl->jointMapUpdated)
		UpdateJointMap();

	auto it = m_impl->jointMap.find(jointName);

	#if NAZARA_UTILITY_SAFE
	if (it == m_impl->jointMap.end())
	{
		NazaraError("Joint not found");
		return nullptr;
	}
	#endif

	return &m_impl->joints[it->second];
}

const NzJoint* NzSkeleton::GetJoint(unsigned int index) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}

	if (index >= m_impl->joints.size())
	{
		NazaraError("Joint index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
		return nullptr;
	}
	#endif

	return &m_impl->joints[index];
}

NzJoint* NzSkeleton::GetJoints()
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}
	#endif

	return &m_impl->joints[0];
}

const NzJoint* NzSkeleton::GetJoints() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return nullptr;
	}
	#endif

	return &m_impl->joints[0];
}

unsigned int NzSkeleton::GetJointCount() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return 0;
	}
	#endif

	return m_impl->joints.size();
}

int NzSkeleton::GetJointIndex(const NzString& jointName) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return -1;
	}
	#endif

	if (!m_impl->jointMapUpdated)
		UpdateJointMap();

	auto it = m_impl->jointMap.find(jointName);

	#if NAZARA_UTILITY_SAFE
	if (it == m_impl->jointMap.end())
	{
		NazaraError("Joint not found");
		return -1;
	}
	#endif

	return it->second;
}

void NzSkeleton::Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return;
	}

	if (!skeletonA.IsValid())
	{
		NazaraError("Skeleton A is invalid");
		return;
	}

	if (!skeletonB.IsValid())
	{
		NazaraError("Skeleton B is invalid");
		return;
	}

	if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount())
	{
		NazaraError("Skeletons must have the same joint count");
		return;
	}
	#endif

	NzJoint* jointsA = &skeletonA.m_impl->joints[0];
	NzJoint* jointsB = &skeletonB.m_impl->joints[0];
	for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
		m_impl->joints[i].Interpolate(jointsA[i], jointsB[i], interpolation);
}

void NzSkeleton::Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation, unsigned int* indices, unsigned int indiceCount)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeleton not created");
		return;
	}

	if (!skeletonA.IsValid())
	{
		NazaraError("Skeleton A is invalid");
		return;
	}

	if (!skeletonB.IsValid())
	{
		NazaraError("Skeleton B is invalid");
		return;
	}

	if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount())
	{
		NazaraError("Skeletons must have the same joint count");
		return;
	}
	#endif

	NzJoint* jointsA = &skeletonA.m_impl->joints[0];
	NzJoint* jointsB = &skeletonB.m_impl->joints[0];
	for (unsigned int i = 0; i < indiceCount; ++i)
	{
		unsigned int index = indices[i];

		#if NAZARA_UTILITY_SAFE
		if (index >= m_impl->joints.size())
		{
			NazaraError("Index #" + NzString::Number(i) + " out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
			return;
		}
		#endif

		m_impl->joints[index].Interpolate(jointsA[index], jointsB[index], interpolation);
	}
}

bool NzSkeleton::IsValid() const
{
	return m_impl != nullptr;
}

NzSkeleton& NzSkeleton::operator=(const NzSkeleton& skeleton)
{
	Destroy();

	if (skeleton.m_impl)
	{
		m_impl = new NzSkeletonImpl;
		m_impl->jointMap = skeleton.m_impl->jointMap;
		m_impl->jointMapUpdated = skeleton.m_impl->jointMapUpdated;
		m_impl->joints = skeleton.m_impl->joints;

		// Code crade mais son optimisation demanderait de stocker jointCount*sizeof(unsigned int) en plus
		// Ce qui, pour juste une copie qui ne se fera que rarement, ne vaut pas le coup
		// L'éternel trade-off mémoire/calculs ..
		unsigned int jointCount = skeleton.m_impl->joints.size();
		for (unsigned int i = 0; i < jointCount; ++i)
		{
			const NzNode* parent = skeleton.m_impl->joints[i].GetParent();
			if (parent)
			{
				for (unsigned int j = 0; j < i; ++j) // Le parent se trouve forcément avant nous
				{
					if (parent == &skeleton.m_impl->joints[j]) // A-t-on trouvé le parent ?
					{
						m_impl->joints[i].SetParent(m_impl->joints[j]); // Oui, tout ça pour ça
						break;
					}
				}
			}
		}
	}

	return *this;
}

void NzSkeleton::InvalidateJointMap()
{
	#ifdef NAZARA_DEBUG
	if (!m_impl)
	{
		NazaraError("Invalid skeleton");
		return;
	}
	#endif

	m_impl->jointMapUpdated = false;
}

void NzSkeleton::UpdateJointMap() const
{
	#ifdef NAZARA_DEBUG
	if (!m_impl)
	{
		NazaraError("Invalid skeleton");
		return;
	}
	#endif

	m_impl->jointMap.clear();
	for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
	{
		NzString name = m_impl->joints[i].GetName();
		if (!name.IsEmpty())
		{
			#if NAZARA_UTILITY_SAFE
			auto it = m_impl->jointMap.find(name);
			if (it != m_impl->jointMap.end())
			{
				NazaraWarning("Joint name \"" + name + "\" is already present in joint map for joint #" + NzString::Number(it->second));
				continue;
			}
			#endif

			m_impl->jointMap[name] = i;
		}
	}

	m_impl->jointMapUpdated = true;
}
<|endoftext|>


<commit_before>#include <rang.hpp>
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
#include <date.h>

#include "Tools/Display/Terminal/Terminal.hpp"

#ifdef ENABLE_MPI
#include <mpi.h>
#endif

#include "Tools/general_utils.h"
#include "Tools/system_functions.h"
#include "Tools/Display/rang_format/rang_format.h"
#include "Tools/Exception/exception.hpp"

#include "Factory/Module/Source/Source.hpp"
#include "Factory/Module/CRC/CRC.hpp"
#include "Factory/Module/Encoder/Encoder.hpp"
#include "Factory/Module/Puncturer/Puncturer.hpp"
#include "Factory/Module/Interleaver/Interleaver.hpp"
#include "Factory/Module/Modem/Modem.hpp"
#include "Factory/Module/Channel/Channel.hpp"
#include "Factory/Module/Quantizer/Quantizer.hpp"
#include "Factory/Module/Decoder/Decoder.hpp"
#include "Factory/Module/Monitor/Monitor.hpp"
#include "Factory/Tools/Display/Terminal/Terminal.hpp"

#include "Launcher.hpp"

using namespace aff3ct;
using namespace aff3ct::launcher;

Launcher::Launcher(const int argc, const char **argv, factory::Simulation::parameters &params_common,
                   std::ostream &stream)
: simu(nullptr), ah(argc, argv), params_common(params_common), stream(stream)
{
	cmd_line += std::string(argv[0]) + std::string(" ");
	for (auto i = 1; i < argc; i++)
	{
		if (argv[i][0] == '-')
			cmd_line += std::string(argv[i]);
		else
			cmd_line += std::string("\"") + std::string(argv[i]) + std::string("\"");

		cmd_line += std::string(" ");
	}
}

Launcher::~Launcher()
{
}

void Launcher::get_description_args()
{
}

void Launcher::store_args()
{
}

int Launcher::read_arguments()
{
	this->get_description_args();

	std::vector<std::string> cmd_error;

	this->arg_vals = ah.parse_arguments(this->args, this->cmd_warn, cmd_error);

	try
	{
		this->store_args();
	}
	catch(const std::exception& e)
	{
		auto save = tools::exception::no_backtrace;
		tools::exception::no_backtrace = true;
		cmd_error.emplace_back(e.what());
		tools::exception::no_backtrace = save;
	}

	if (params_common.display_help)
	{
		auto grps = factory::Factory::create_groups({&params_common});
		ah.print_help(this->args, grps, params_common.display_adv_help);
	}

	// print usage
	if (!cmd_error.empty() && !params_common.display_help)
		ah.print_usage(this->args);

	// print the errors
	if (!cmd_error.empty()) std::cerr << std::endl;
	for (unsigned e = 0; e < cmd_error.size(); e++)
		std::cerr << rang::tag::error << cmd_error[e] << std::endl;

	// print the help tags
	if (!cmd_error.empty() && !params_common.display_help)
	{
		tools::Argument_tag help_tag = {"help", "h"};

		std::string message = "For more information please display the help (\"";
		message += tools::Argument_handler::print_tag(help_tag) += "\").";

		std::cerr << std::endl << rang::tag::info << message << std::endl;
	}

	return (!cmd_error.empty() || params_common.display_help) ? EXIT_FAILURE : EXIT_SUCCESS;
}

void Launcher::print_header()
{
	// display configuration and simulation parameters
	stream << rang::tag::comment << rang::style::bold << "----------------------------------------------------" << std::endl;
	stream << rang::tag::comment << rang::style::bold << "---- A FAST FORWARD ERROR CORRECTION TOOLBOX >> ----" << std::endl;
	stream << rang::tag::comment << rang::style::bold << "----------------------------------------------------" << std::endl;
	stream << rang::tag::comment << rang::style::bold << rang::style::underline << "Parameters :"<< rang::style::reset << std::endl;
	factory::Header::print_parameters({&params_common}, false, this->stream);
	this->stream << rang::tag::comment << std::endl;
}

int Launcher::launch()
{
	int exit_code = EXIT_SUCCESS;

	std::srand((unsigned)this->params_common.global_seed);

	// in case of the user call launch multiple times
	if (simu != nullptr)
	{
		delete simu;
		simu = nullptr;
	}

	if (this->read_arguments() == EXIT_FAILURE)
	{
		// print the warnings
#ifdef ENABLE_MPI
		if (this->params_common.mpi_rank == 0)
#endif
			for (unsigned w = 0; w < this->cmd_warn.size(); w++)
				std::clog << rang::tag::warning << this->cmd_warn[w] << std::endl;
		return EXIT_FAILURE;
	}

	// write the command and he curve name in the PyBER format
#ifdef ENABLE_MPI
	if (!this->params_common.pyber.empty() && this->params_common.mpi_rank == 0)
#else
	if (!this->params_common.pyber.empty())
#endif
	{
		stream << "Run command:"            << std::endl;
		stream << cmd_line                  << std::endl;
		stream << "Curve name:"             << std::endl;
		stream << this->params_common.pyber << std::endl;
		stream << "Trace:"                  << std::endl;
	}

	if (this->params_common.display_legend)
#ifdef ENABLE_MPI
		if (this->params_common.mpi_rank == 0)
#endif
			this->print_header();

	// print the warnings
#ifdef ENABLE_MPI
	if (this->params_common.mpi_rank == 0)
#endif
		for (unsigned w = 0; w < this->cmd_warn.size(); w++)
			std::clog << rang::tag::warning << this->cmd_warn[w] << std::endl;

	try
	{
		simu = this->build_simu();
	}
	catch(const std::exception& e)
	{
		rang::format_on_each_line(std::cerr, std::string(e.what()) + "\n", rang::tag::error);
		exit_code = EXIT_FAILURE;
	}

	if (simu != nullptr)
	{
		// launch the simulation
		if (this->params_common.display_legend)
#ifdef ENABLE_MPI
			if (this->params_common.mpi_rank == 0)
#endif
				stream << rang::tag::comment << "The simulation is running..." << std::endl;

		try
		{
			simu->launch();
			if (simu->is_error())
				exit_code = EXIT_FAILURE;
		}
		catch(const std::exception& e)
		{
			rang::format_on_each_line(std::cerr, std::string(e.what()) + "\n", rang::tag::error);
			exit_code = EXIT_FAILURE;
		}
	}

	if (this->params_common.display_legend)
#ifdef ENABLE_MPI
		if (this->params_common.mpi_rank == 0)
#endif
			stream << rang::tag::comment << "End of the simulation." << std::endl;

	if (simu != nullptr)
	{
		delete simu;
		simu = nullptr;
	}

	return exit_code;
}
<commit_msg>Do not display factory errors when on mpi on others nodes<commit_after>#include <rang.hpp>
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
#include <date.h>

#include "Tools/Display/Terminal/Terminal.hpp"

#ifdef ENABLE_MPI
#include <mpi.h>
#endif

#include "Tools/general_utils.h"
#include "Tools/system_functions.h"
#include "Tools/Display/rang_format/rang_format.h"
#include "Tools/Exception/exception.hpp"

#include "Factory/Module/Source/Source.hpp"
#include "Factory/Module/CRC/CRC.hpp"
#include "Factory/Module/Encoder/Encoder.hpp"
#include "Factory/Module/Puncturer/Puncturer.hpp"
#include "Factory/Module/Interleaver/Interleaver.hpp"
#include "Factory/Module/Modem/Modem.hpp"
#include "Factory/Module/Channel/Channel.hpp"
#include "Factory/Module/Quantizer/Quantizer.hpp"
#include "Factory/Module/Decoder/Decoder.hpp"
#include "Factory/Module/Monitor/Monitor.hpp"
#include "Factory/Tools/Display/Terminal/Terminal.hpp"

#include "Launcher.hpp"

using namespace aff3ct;
using namespace aff3ct::launcher;

Launcher::Launcher(const int argc, const char **argv, factory::Simulation::parameters &params_common,
                   std::ostream &stream)
: simu(nullptr), ah(argc, argv), params_common(params_common), stream(stream)
{
	cmd_line += std::string(argv[0]) + std::string(" ");
	for (auto i = 1; i < argc; i++)
	{
		if (argv[i][0] == '-')
			cmd_line += std::string(argv[i]);
		else
			cmd_line += std::string("\"") + std::string(argv[i]) + std::string("\"");

		cmd_line += std::string(" ");
	}
}

Launcher::~Launcher()
{
}

void Launcher::get_description_args()
{
}

void Launcher::store_args()
{
}

int Launcher::read_arguments()
{
	this->get_description_args();

	std::vector<std::string> cmd_error;

	this->arg_vals = ah.parse_arguments(this->args, this->cmd_warn, cmd_error);

	try
	{
		this->store_args();
	}
	catch(const std::exception& e)
	{
		auto save = tools::exception::no_backtrace;
		tools::exception::no_backtrace = true;
		cmd_error.emplace_back(e.what());
		tools::exception::no_backtrace = save;
	}

#ifdef ENABLE_MPI
	if (this->params_common.mpi_rank == 0)
	{
#endif
		if (params_common.display_help)
		{
			auto grps = factory::Factory::create_groups({&params_common});
			ah.print_help(this->args, grps, params_common.display_adv_help);
		}

		// print usage
		if (!cmd_error.empty() && !params_common.display_help)
			ah.print_usage(this->args);

		// print the errors
		if (!cmd_error.empty()) std::cerr << std::endl;
		for (unsigned e = 0; e < cmd_error.size(); e++)
			std::cerr << rang::tag::error << cmd_error[e] << std::endl;

		// print the help tags
		if (!cmd_error.empty() && !params_common.display_help)
		{
			tools::Argument_tag help_tag = {"help", "h"};

			std::string message = "For more information please display the help (\"";
			message += tools::Argument_handler::print_tag(help_tag) += "\").";

			std::cerr << std::endl << rang::tag::info << message << std::endl;
		}
#ifdef ENABLE_MPI
	}
#endif

	return (!cmd_error.empty() || params_common.display_help) ? EXIT_FAILURE : EXIT_SUCCESS;
}

void Launcher::print_header()
{
	// display configuration and simulation parameters
	stream << rang::tag::comment << rang::style::bold << "----------------------------------------------------" << std::endl;
	stream << rang::tag::comment << rang::style::bold << "---- A FAST FORWARD ERROR CORRECTION TOOLBOX >> ----" << std::endl;
	stream << rang::tag::comment << rang::style::bold << "----------------------------------------------------" << std::endl;
	stream << rang::tag::comment << rang::style::bold << rang::style::underline << "Parameters :"<< rang::style::reset << std::endl;
	factory::Header::print_parameters({&params_common}, false, this->stream);
	this->stream << rang::tag::comment << std::endl;
}

int Launcher::launch()
{
	int exit_code = EXIT_SUCCESS;

	std::srand((unsigned)this->params_common.global_seed);

	// in case of the user call launch multiple times
	if (simu != nullptr)
	{
		delete simu;
		simu = nullptr;
	}

	if (this->read_arguments() == EXIT_FAILURE)
	{
		// print the warnings
#ifdef ENABLE_MPI
		if (this->params_common.mpi_rank == 0)
#endif
			for (unsigned w = 0; w < this->cmd_warn.size(); w++)
				std::clog << rang::tag::warning << this->cmd_warn[w] << std::endl;
		return EXIT_FAILURE;
	}

	// write the command and he curve name in the PyBER format
#ifdef ENABLE_MPI
	if (this->params_common.mpi_rank == 0)
#endif
	if (!this->params_common.pyber.empty())
	{
		stream << "Run command:"            << std::endl;
		stream << cmd_line                  << std::endl;
		stream << "Curve name:"             << std::endl;
		stream << this->params_common.pyber << std::endl;
		stream << "Trace:"                  << std::endl;
	}

	if (this->params_common.display_legend)
#ifdef ENABLE_MPI
		if (this->params_common.mpi_rank == 0)
#endif
			this->print_header();

	// print the warnings
#ifdef ENABLE_MPI
	if (this->params_common.mpi_rank == 0)
#endif
		for (unsigned w = 0; w < this->cmd_warn.size(); w++)
			std::clog << rang::tag::warning << this->cmd_warn[w] << std::endl;

	try
	{
		simu = this->build_simu();
	}
	catch(const std::exception& e)
	{
		rang::format_on_each_line(std::cerr, std::string(e.what()) + "\n", rang::tag::error);
		exit_code = EXIT_FAILURE;
	}

	if (simu != nullptr)
	{
		// launch the simulation
		if (this->params_common.display_legend)
#ifdef ENABLE_MPI
			if (this->params_common.mpi_rank == 0)
#endif
				stream << rang::tag::comment << "The simulation is running..." << std::endl;

		try
		{
			simu->launch();
			if (simu->is_error())
				exit_code = EXIT_FAILURE;
		}
		catch(const std::exception& e)
		{
			rang::format_on_each_line(std::cerr, std::string(e.what()) + "\n", rang::tag::error);
			exit_code = EXIT_FAILURE;
		}
	}

	if (this->params_common.display_legend)
#ifdef ENABLE_MPI
		if (this->params_common.mpi_rank == 0)
#endif
			stream << rang::tag::comment << "End of the simulation." << std::endl;

	if (simu != nullptr)
	{
		delete simu;
		simu = nullptr;
	}

	return exit_code;
}
<|endoftext|>


<commit_before><commit_msg>vcl: change to true and false in Window::SetCallHandlersOnInputDisabled()<commit_after><|endoftext|>