<commit_before>#include "./labeller.h"
#include <Eigen/Geometry>
#include <vector>
#include "../utils/cuda_array_provider.h"
#include "./summed_area_table.h"

namespace Placement
{

Labeller::Labeller(std::shared_ptr<Labels> labels) : labels(labels)
{
}

void
Labeller::initialize(std::shared_ptr<CudaArrayProvider> occupancyTextureMapper)
{
  occupancySummedAreaTable =
      std::make_shared<SummedAreaTable>(occupancyTextureMapper);
}

void Labeller::setInsertionOrder(std::vector<int> ids)
{
  insertionOrder = ids;
}

std::map<int, Eigen::Vector3f>
Labeller::update(const LabellerFrameData &frameData)
{
  std::map<int, Eigen::Vector3f> result;
  if (!occupancySummedAreaTable.get())
    return result;

  occupancySummedAreaTable->runKernel();

  Eigen::Matrix4f inverseViewProjection = frameData.viewProjection.inverse();

  // TODO(SIR): iterate through labels specific order according to apollonius.
  for (auto id : insertionOrder)
  {
    auto label = labels->getById(id);
    auto anchor2D = frameData.project(label.anchorPosition);
    float x = (anchor2D.x() * 0.5f + 0.5f) * width;
    float y = (anchor2D.y() * 0.5f + 0.5f) * height;

    auto newPosition = costFunctionCalculator.calculateForLabel(
        occupancySummedAreaTable->getResults(), label.id, x, y, label.size.x(),
        label.size.y());

    // TODO(SIR): update occupancy and recalculate SAT or incorporate labels
    // somehow directly in occupancy calculation in CostFunctionCalculator.

    float newX = (std::get<0>(newPosition) / width - 0.5f) * 2.0f;
    float newY = (std::get<1>(newPosition) / height - 0.5f) * 2.0f;
    Eigen::Vector4f reprojected =
        inverseViewProjection * Eigen::Vector4f(newX, newY, anchor2D.z(), 1);
    reprojected /= reprojected.w();

    result[label.id] = toVector3f(reprojected);
  }

  return result;
}

void Labeller::resize(int width, int height)
{
  this->width = width;
  this->height = height;

  costFunctionCalculator.resize(width, height);
}

}  // namespace Placement
<commit_msg>Set approximate label size. Before the given size was in world units.<commit_after>#include "./labeller.h"
#include <Eigen/Geometry>
#include <vector>
#include "../utils/cuda_array_provider.h"
#include "./summed_area_table.h"

namespace Placement
{

Labeller::Labeller(std::shared_ptr<Labels> labels) : labels(labels)
{
}

void
Labeller::initialize(std::shared_ptr<CudaArrayProvider> occupancyTextureMapper)
{
  occupancySummedAreaTable =
      std::make_shared<SummedAreaTable>(occupancyTextureMapper);
}

void Labeller::setInsertionOrder(std::vector<int> ids)
{
  insertionOrder = ids;
}

std::map<int, Eigen::Vector3f>
Labeller::update(const LabellerFrameData &frameData)
{
  std::map<int, Eigen::Vector3f> result;
  if (!occupancySummedAreaTable.get())
    return result;

  occupancySummedAreaTable->runKernel();

  Eigen::Matrix4f inverseViewProjection = frameData.viewProjection.inverse();

  // TODO(SIR): iterate through labels specific order according to apollonius.
  for (auto id : insertionOrder)
  {
    auto label = labels->getById(id);
    auto anchor2D = frameData.project(label.anchorPosition);
    float x = (anchor2D.x() * 0.5f + 0.5f) * width;
    float y = (anchor2D.y() * 0.5f + 0.5f) * height;

    auto newPosition = costFunctionCalculator.calculateForLabel(
        occupancySummedAreaTable->getResults(), label.id, x, y,
        label.size.x() * width, label.size.y() * height);

    // TODO(SIR): update occupancy and recalculate SAT or incorporate labels
    // somehow directly in occupancy calculation in CostFunctionCalculator.

    float newX = (std::get<0>(newPosition) / width - 0.5f) * 2.0f;
    float newY = (std::get<1>(newPosition) / height - 0.5f) * 2.0f;
    Eigen::Vector4f reprojected =
        inverseViewProjection * Eigen::Vector4f(newX, newY, anchor2D.z(), 1);
    reprojected /= reprojected.w();

    result[label.id] = toVector3f(reprojected);
  }

  return result;
}

void Labeller::resize(int width, int height)
{
  this->width = width;
  this->height = height;

  costFunctionCalculator.resize(width, height);
}

}  // namespace Placement
<|endoftext|>


<commit_before>/**
 * @file hybrid_height.cpp
 *
 * @date Apr 5, 2013
 * @author peramaki
 */

#include "hybrid_height.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "neons.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace std;
using namespace himan::plugin;

const string itsName("hybrid_height");

hybrid_height::hybrid_height() : itsFastMode(false)
{
	itsClearTextFormula = "HEIGHT = prevH + (287/9.81) * (T+prevT)/2 * log(prevP / P)";
	itsLogger = logger_factory::Instance()->GetLog(itsName);

}

void hybrid_height::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	SetParams({param("HL-M", 3, 0, 3, 6)});

	/*
	 * For hybrid height we must go through the levels backwards.
	 */

	itsInfo->LevelOrder(kBottomToTop);

	shared_ptr<neons> theNeons = dynamic_pointer_cast <neons> (plugin_factory::Instance()->Plugin("neons"));

	itsBottomLevel = boost::lexical_cast<int> (theNeons->ProducerMetaData(itsConfiguration->SourceProducer().Id(), "last hybrid level number"));

	itsUseGeopotential = (itsConfiguration->SourceProducer().Id() == 1 || itsConfiguration->SourceProducer().Id() == 199);

	if (!itsConfiguration->Exists("fast_mode") && itsConfiguration->GetValue("fast_mode") == "true")
	{
		itsFastMode = true;
	}
	else if (!itsUseGeopotential)
	{
		// When doing exact calculation we must do them sequentially starting from
		// surface closest to ground because every surface's value is depended
		// on the surface below it. Therefore we cannot parallelize the calculation
		// on level basis.

		if (Dimension() != kTimeDimension)
		{
			itsLogger->Info("Changing leading_dimension to time");
			Dimension(kTimeDimension);
		}
	}

	Start();

}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void hybrid_height::Calculate(shared_ptr<info> myTargetInfo, unsigned short threadIndex)
{

	const params GPParam { param("PGR-PA"), param("P-PA") };
	const param PParam("P-HPA");
	const params TParam = { param("T-K"), param("TG-K") };
	const param ZParam("Z-M2S2");

	level H2;//(himan::kHeight, 2, "HEIGHT");
	level H0;//(himan::kHeight, 0, "HEIGHT");
	if ( itsConfiguration->SourceProducer().Id() == 131)
	{
		H2 = level(himan::kGround, 0, "GROUND");
		H0 = level(himan::kGround, 0, "GROUND");
	}
	else
	{
		H2 = level(himan::kHeight, 2, "HEIGHT");
		H0 = level(himan::kHeight, 0, "HEIGHT");
	}

	auto myThreadedLogger = logger_factory::Instance()->GetLog(itsName + "Thread #" + boost::lexical_cast<string> (threadIndex));

	forecast_time forecastTime = myTargetInfo->Time();
	level forecastLevel = myTargetInfo->Level();

	myThreadedLogger->Info("Calculating time " + static_cast<string>(*forecastTime.ValidDateTime()) + " level " + static_cast<string> (forecastLevel));

	/*
		pitääkö tunnistaa tuottaja?
	*/

	level prevLevel;

	bool firstLevel = false;

	if (itsFastMode || myTargetInfo->Level().Value() == itsBottomLevel)
	{
		firstLevel = true;
	}
	else
	{
		prevLevel = level(myTargetInfo->Level());
		prevLevel.Value(myTargetInfo->Level().Value() + 1);

		prevLevel.Index(prevLevel.Index() + 1);
	}

	info_t TInfo, PInfo, prevPInfo, prevTInfo, prevHInfo, GPInfo, zeroGPInfo;

	if (itsUseGeopotential)
	{
		GPInfo = Fetch(forecastTime, forecastLevel, ZParam, false);
		zeroGPInfo = Fetch(forecastTime, H0, ZParam, false);

		SetAB(myTargetInfo, GPInfo);

	}
	else
	{

		if (!firstLevel)
		{
			prevTInfo = Fetch(forecastTime, prevLevel, TParam, false);
			prevPInfo = Fetch(forecastTime, prevLevel, PParam, false);
			prevHInfo = Fetch(forecastTime, prevLevel, param("HL-M"), false);
		}
		else
		{
			prevPInfo = Fetch(forecastTime, H0, GPParam, false);
			prevTInfo = Fetch(forecastTime, H2, TParam, false);
		}

		PInfo = Fetch(forecastTime, forecastLevel, PParam, false);
		TInfo = Fetch(forecastTime, forecastLevel, TParam, false);

		assert(PInfo->Grid()->AB() == TInfo->Grid()->AB());

		SetAB(myTargetInfo, TInfo);

	}

	if ((itsUseGeopotential && (!GPInfo || !zeroGPInfo)) || (!itsUseGeopotential && (!prevTInfo || !prevPInfo || ( !prevHInfo && !firstLevel ) || !PInfo || !TInfo)))
	{
		myThreadedLogger->Warning("Skipping step " + boost::lexical_cast<string> (forecastTime.Step()) + ", level " + static_cast<string> (forecastLevel));
		return;
	}

	string deviceType = "CPU";

	if (itsUseGeopotential)
	{
		GPInfo->ResetLocation();
		zeroGPInfo->ResetLocation();
	}
	else
	{
		PInfo->ResetLocation();
		TInfo->ResetLocation();
		prevPInfo->ResetLocation();
		prevTInfo->ResetLocation();
		if (!firstLevel)
		{
			prevHInfo->ResetLocation();
		}
	}

	LOCKSTEP(myTargetInfo)
	{

		if (itsUseGeopotential)
		{
			GPInfo->NextLocation();
			double GP = GPInfo->Value();

			zeroGPInfo->NextLocation();
			double zeroGP = zeroGPInfo->Value();

			if (GP == kFloatMissing || zeroGP == kFloatMissing)
			{
				continue;
			}

			double height = (GP - zeroGP) * himan::constants::kIg;

			myTargetInfo->Value(height);
		}
		else
		{
			TInfo->NextLocation();
			double T = TInfo->Value();

			PInfo->NextLocation();
			double P = PInfo->Value();

			prevTInfo->NextLocation();
			double prevT = prevTInfo->Value();

			prevPInfo->NextLocation();
			double prevP = prevPInfo->Value();

			double prevH = kFloatMissing;

			if (!firstLevel)
			{

				prevHInfo->NextLocation();
				prevH = prevHInfo->Value();

				if (prevH == kFloatMissing )
				{
					continue;
				}
			}

			if (prevT == kFloatMissing || prevP == kFloatMissing || T == kFloatMissing || P == kFloatMissing )
			{
				continue;
			}

			if (firstLevel )//&& !itsConfiguration->SourceProducer().Id() == 131)
			{
				prevP /= 100.f;
			}

			double Tave = ( T + prevT ) / 2;
			cout << "prevP: ";
			cout << prevP << endl;
			cout << "P: ";
			cout << P << endl;
			double deltaZ = (287 / 9.81) * Tave * log(prevP / P);
			cout << "D: ";
			cout << deltaZ << endl;
			double totalHeight(0);

			if (firstLevel)
			{
				totalHeight = deltaZ;
			}
			else
			{
				totalHeight = prevH + deltaZ;
			}

			myTargetInfo->Value(totalHeight);

		}
	}

	if (!itsFastMode)
	{
		firstLevel = false;
	}

	myThreadedLogger->Info("[" + deviceType + "] Missing values: " + boost::lexical_cast<string> (myTargetInfo->Data()->MissingCount()) + "/" + boost::lexical_cast<string> (myTargetInfo->Data()->Size()));

}
<commit_msg>couts away!<commit_after>/**
 * @file hybrid_height.cpp
 *
 * @date Apr 5, 2013
 * @author peramaki
 */

#include "hybrid_height.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "neons.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace std;
using namespace himan::plugin;

const string itsName("hybrid_height");

hybrid_height::hybrid_height() : itsFastMode(false)
{
	itsClearTextFormula = "HEIGHT = prevH + (287/9.81) * (T+prevT)/2 * log(prevP / P)";
	itsLogger = logger_factory::Instance()->GetLog(itsName);

}

void hybrid_height::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	SetParams({param("HL-M", 3, 0, 3, 6)});

	/*
	 * For hybrid height we must go through the levels backwards.
	 */

	itsInfo->LevelOrder(kBottomToTop);

	shared_ptr<neons> theNeons = dynamic_pointer_cast <neons> (plugin_factory::Instance()->Plugin("neons"));

	itsBottomLevel = boost::lexical_cast<int> (theNeons->ProducerMetaData(itsConfiguration->SourceProducer().Id(), "last hybrid level number"));

	itsUseGeopotential = (itsConfiguration->SourceProducer().Id() == 1 || itsConfiguration->SourceProducer().Id() == 199);

	if (!itsConfiguration->Exists("fast_mode") && itsConfiguration->GetValue("fast_mode") == "true")
	{
		itsFastMode = true;
	}
	else if (!itsUseGeopotential)
	{
		// When doing exact calculation we must do them sequentially starting from
		// surface closest to ground because every surface's value is depended
		// on the surface below it. Therefore we cannot parallelize the calculation
		// on level basis.

		if (Dimension() != kTimeDimension)
		{
			itsLogger->Info("Changing leading_dimension to time");
			Dimension(kTimeDimension);
		}
	}

	Start();

}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void hybrid_height::Calculate(shared_ptr<info> myTargetInfo, unsigned short threadIndex)
{

	const params GPParam { param("PGR-PA"), param("P-PA") };
	const param PParam("P-HPA");
	const params TParam = { param("T-K"), param("TG-K") };
	const param ZParam("Z-M2S2");

	level H2;//(himan::kHeight, 2, "HEIGHT");
	level H0;//(himan::kHeight, 0, "HEIGHT");
	if ( itsConfiguration->SourceProducer().Id() == 131)
	{
		H2 = level(himan::kGround, 0, "GROUND");
		H0 = level(himan::kGround, 0, "GROUND");
	}
	else
	{
		H2 = level(himan::kHeight, 2, "HEIGHT");
		H0 = level(himan::kHeight, 0, "HEIGHT");
	}

	auto myThreadedLogger = logger_factory::Instance()->GetLog(itsName + "Thread #" + boost::lexical_cast<string> (threadIndex));

	forecast_time forecastTime = myTargetInfo->Time();
	level forecastLevel = myTargetInfo->Level();

	myThreadedLogger->Info("Calculating time " + static_cast<string>(*forecastTime.ValidDateTime()) + " level " + static_cast<string> (forecastLevel));

	/*
		pitääkö tunnistaa tuottaja?
	*/

	level prevLevel;

	bool firstLevel = false;

	if (itsFastMode || myTargetInfo->Level().Value() == itsBottomLevel)
	{
		firstLevel = true;
	}
	else
	{
		prevLevel = level(myTargetInfo->Level());
		prevLevel.Value(myTargetInfo->Level().Value() + 1);

		prevLevel.Index(prevLevel.Index() + 1);
	}

	info_t TInfo, PInfo, prevPInfo, prevTInfo, prevHInfo, GPInfo, zeroGPInfo;

	if (itsUseGeopotential)
	{
		GPInfo = Fetch(forecastTime, forecastLevel, ZParam, false);
		zeroGPInfo = Fetch(forecastTime, H0, ZParam, false);

		SetAB(myTargetInfo, GPInfo);

	}
	else
	{

		if (!firstLevel)
		{
			prevTInfo = Fetch(forecastTime, prevLevel, TParam, false);
			prevPInfo = Fetch(forecastTime, prevLevel, PParam, false);
			prevHInfo = Fetch(forecastTime, prevLevel, param("HL-M"), false);
		}
		else
		{
			prevPInfo = Fetch(forecastTime, H0, GPParam, false);
			prevTInfo = Fetch(forecastTime, H2, TParam, false);
		}

		PInfo = Fetch(forecastTime, forecastLevel, PParam, false);
		TInfo = Fetch(forecastTime, forecastLevel, TParam, false);

		assert(PInfo->Grid()->AB() == TInfo->Grid()->AB());

		SetAB(myTargetInfo, TInfo);

	}

	if ((itsUseGeopotential && (!GPInfo || !zeroGPInfo)) || (!itsUseGeopotential && (!prevTInfo || !prevPInfo || ( !prevHInfo && !firstLevel ) || !PInfo || !TInfo)))
	{
		myThreadedLogger->Warning("Skipping step " + boost::lexical_cast<string> (forecastTime.Step()) + ", level " + static_cast<string> (forecastLevel));
		return;
	}

	string deviceType = "CPU";

	if (itsUseGeopotential)
	{
		GPInfo->ResetLocation();
		zeroGPInfo->ResetLocation();
	}
	else
	{
		PInfo->ResetLocation();
		TInfo->ResetLocation();
		prevPInfo->ResetLocation();
		prevTInfo->ResetLocation();
		if (!firstLevel)
		{
			prevHInfo->ResetLocation();
		}
	}

	LOCKSTEP(myTargetInfo)
	{

		if (itsUseGeopotential)
		{
			GPInfo->NextLocation();
			double GP = GPInfo->Value();

			zeroGPInfo->NextLocation();
			double zeroGP = zeroGPInfo->Value();

			if (GP == kFloatMissing || zeroGP == kFloatMissing)
			{
				continue;
			}

			double height = (GP - zeroGP) * himan::constants::kIg;

			myTargetInfo->Value(height);
		}
		else
		{
			TInfo->NextLocation();
			double T = TInfo->Value();

			PInfo->NextLocation();
			double P = PInfo->Value();

			prevTInfo->NextLocation();
			double prevT = prevTInfo->Value();

			prevPInfo->NextLocation();
			double prevP = prevPInfo->Value();

			double prevH = kFloatMissing;

			if (!firstLevel)
			{

				prevHInfo->NextLocation();
				prevH = prevHInfo->Value();

				if (prevH == kFloatMissing )
				{
					continue;
				}
			}

			if (prevT == kFloatMissing || prevP == kFloatMissing || T == kFloatMissing || P == kFloatMissing )
			{
				continue;
			}

			if (firstLevel )//&& !itsConfiguration->SourceProducer().Id() == 131)
			{
				prevP /= 100.f;
			}

			double Tave = ( T + prevT ) / 2;
			double deltaZ = (287 / 9.81) * Tave * log(prevP / P);
			double totalHeight(0);

			if (firstLevel)
			{
				totalHeight = deltaZ;
			}
			else
			{
				totalHeight = prevH + deltaZ;
			}

			myTargetInfo->Value(totalHeight);

		}
	}

	if (!itsFastMode)
	{
		firstLevel = false;
	}

	myThreadedLogger->Info("[" + deviceType + "] Missing values: " + boost::lexical_cast<string> (myTargetInfo->Data()->MissingCount()) + "/" + boost::lexical_cast<string> (myTargetInfo->Data()->Size()));

}
<|endoftext|>


<commit_before>/**
 * @file monin_obukhov.cpp
 *
 * Claculates the inverse of the Monin-Obukhov length.
 *
 * @date Aug 8, 2014
 * @author Tack
 */

#include <boost/lexical_cast.hpp>

#include "monin_obukhov.h"
#include "logger_factory.h"
#include "level.h"
#include "forecast_time.h"
#include "logger_factory.h"

using namespace std;
using namespace himan::plugin;

monin_obukhov::monin_obukhov()
{
	itsClearTextFormula = "1/L = -(k*g*Q)/(u*^3*T)";

	itsLogger = logger_factory::Instance()->GetLog("monin_obukhov");
}

void monin_obukhov::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	/*
	 * Set target parameter properties
	 * - name PARM_NAME, this name is found from neons. For example: T-K
	 * - univ_id UNIV_ID, newbase-id, ie code table 204
	 * - grib1 id must be in database
	 * - grib2 descriptor X'Y'Z, http://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_table4-2.shtml
	 *
	 */

	param theRequestedParam("MOL-M", 1204);

	// If this param is also used as a source param for other calculations

	SetParams({theRequestedParam});

	Start();
}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void monin_obukhov::Calculate(shared_ptr<info> myTargetInfo, unsigned short threadIndex)
{

	/*
	 * Required source parameters
	 *
	 * eg. param PParam("P-Pa"); for pressure in pascals
	 *
	 */

	const param TParam("T-K"); // ground Temperature
	const param QParam("FLSEN-JM2"); // surface heat flux
	const param U_SParam("FRVEL-MS"); // friction velocity

	// ----

	auto myThreadedLogger = logger_factory::Instance()->GetLog("monin_obukhov Thread #" + boost::lexical_cast<string> (threadIndex));

	// Current time and level

	forecast_time forecastTime = myTargetInfo->Time();
	level forecastLevel = level(himan::kHeight, 0, "Height");

	myThreadedLogger->Debug("Calculating time " + static_cast<string> (*forecastTime.ValidDateTime()) + " level " + static_cast<string> (forecastLevel));

	info_t TInfo = Fetch(forecastTime, forecastLevel, TParam, false);
	info_t QInfo = Fetch(forecastTime, forecastLevel, QParam, false);
	info_t U_SInfo = Fetch(forecastTime, forecastLevel, U_SParam, false);

	// determine length of forecast step to calculate surface heat flux in W/m2
	double forecastStepSize;

	if ( itsConfiguration->SourceProducer().Id() != 199)
	{
		forecastStepSize = itsConfiguration->ForecastStep()*3600; //step size in seconds
	}
	else
	{
		forecastStepSize = itsConfiguration->ForecastStep()*60; //step size in seconds
	}

	if (!TInfo || !QInfo || !U_SInfo)
	{
		myThreadedLogger->Info("Skipping step " + boost::lexical_cast<string> (forecastTime.Step()) + ", level " + static_cast<string> (forecastLevel));

		if (itsConfiguration->StatisticsEnabled())
		{
			// When time or level is skipped, all values are missing
			itsConfiguration->Statistics()->AddToMissingCount(myTargetInfo->Data()->Size());
			itsConfiguration->Statistics()->AddToValueCount(myTargetInfo->Data()->Size());
		}

		return;

	}

	string deviceType = "CPU";

	LOCKSTEP(myTargetInfo, TInfo, QInfo, U_SInfo)
	{

		double T = TInfo->Value();
		double Q = QInfo->Value()/forecastStepSize; // divide by time step to obtain Watts
		double U_S = U_SInfo->Value();

		double mol(kFloatMissing);

		if (T == kFloatMissing || Q == kFloatMissing || U_S == kFloatMissing)
		{
			continue;
		}

		/* Calculation of the inverse of Monin-Obukhov length to avoid division by 0 */

		if (U_S != 0.0)
		{
			mol = -constants::kG * constants::kK * Q / (U_S * U_S * U_S * T);
		}
		myTargetInfo->Value(1/mol);

	}

	myThreadedLogger->Info("[" + deviceType + "] Missing values: " + boost::lexical_cast<string> (myTargetInfo->Data()->MissingCount()) + "/" + boost::lexical_cast<string> (myTargetInfo->Data()->Size()));

}
<commit_msg>Calculate inverse<commit_after>/**
 * @file monin_obukhov.cpp
 *
 * Claculates the inverse of the Monin-Obukhov length.
 *
 * @date Aug 8, 2014
 * @author Tack
 */

#include <boost/lexical_cast.hpp>

#include "monin_obukhov.h"
#include "logger_factory.h"
#include "level.h"
#include "forecast_time.h"
#include "logger_factory.h"

using namespace std;
using namespace himan::plugin;

monin_obukhov::monin_obukhov()
{
	itsClearTextFormula = "1/L = -(k*g*Q)/(u*^3*T)";

	itsLogger = logger_factory::Instance()->GetLog("monin_obukhov");
}

void monin_obukhov::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	/*
	 * Set target parameter properties
	 * - name PARM_NAME, this name is found from neons. For example: T-K
	 * - univ_id UNIV_ID, newbase-id, ie code table 204
	 * - grib1 id must be in database
	 * - grib2 descriptor X'Y'Z, http://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_table4-2.shtml
	 *
	 */

	param theRequestedParam("MOL-M", 1204);

	// If this param is also used as a source param for other calculations

	SetParams({theRequestedParam});

	Start();
}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void monin_obukhov::Calculate(shared_ptr<info> myTargetInfo, unsigned short threadIndex)
{

	/*
	 * Required source parameters
	 *
	 * eg. param PParam("P-Pa"); for pressure in pascals
	 *
	 */

	const param TParam("T-K"); // ground Temperature
	const param QParam("FLSEN-JM2"); // surface heat flux
	const param U_SParam("FRVEL-MS"); // friction velocity

	// ----

	auto myThreadedLogger = logger_factory::Instance()->GetLog("monin_obukhov Thread #" + boost::lexical_cast<string> (threadIndex));

	// Current time and level

	forecast_time forecastTime = myTargetInfo->Time();
	level forecastLevel = level(himan::kHeight, 0, "Height");

	myThreadedLogger->Debug("Calculating time " + static_cast<string> (*forecastTime.ValidDateTime()) + " level " + static_cast<string> (forecastLevel));

	info_t TInfo = Fetch(forecastTime, forecastLevel, TParam, false);
	info_t QInfo = Fetch(forecastTime, forecastLevel, QParam, false);
	info_t U_SInfo = Fetch(forecastTime, forecastLevel, U_SParam, false);

	// determine length of forecast step to calculate surface heat flux in W/m2
	double forecastStepSize;

	if ( itsConfiguration->SourceProducer().Id() != 199)
	{
		forecastStepSize = itsConfiguration->ForecastStep()*3600; //step size in seconds
	}
	else
	{
		forecastStepSize = itsConfiguration->ForecastStep()*60; //step size in seconds
	}

	if (!TInfo || !QInfo || !U_SInfo)
	{
		myThreadedLogger->Info("Skipping step " + boost::lexical_cast<string> (forecastTime.Step()) + ", level " + static_cast<string> (forecastLevel));

		if (itsConfiguration->StatisticsEnabled())
		{
			// When time or level is skipped, all values are missing
			itsConfiguration->Statistics()->AddToMissingCount(myTargetInfo->Data()->Size());
			itsConfiguration->Statistics()->AddToValueCount(myTargetInfo->Data()->Size());
		}

		return;

	}

	string deviceType = "CPU";

	LOCKSTEP(myTargetInfo, TInfo, QInfo, U_SInfo)
	{

		double T = TInfo->Value();
		double Q = QInfo->Value()/forecastStepSize; // divide by time step to obtain Watts
		double U_S = U_SInfo->Value();

		double mol(kFloatMissing);

		if (T == kFloatMissing || Q == kFloatMissing || U_S == kFloatMissing)
		{
			continue;
		}

		/* Calculation of the inverse of Monin-Obukhov length to avoid division by 0 */

		if (U_S != 0.0)
		{
			mol = -constants::kG * constants::kK * Q / (U_S * U_S * U_S * T);
		}
		myTargetInfo->Value(mol);

	}

	myThreadedLogger->Info("[" + deviceType + "] Missing values: " + boost::lexical_cast<string> (myTargetInfo->Data()->MissingCount()) + "/" + boost::lexical_cast<string> (myTargetInfo->Data()->Size()));

}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/build/linker/gensyms.C $                                  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2013,2015                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#include <string>
#include <stdint.h>
#include <cstring>
#include <endian.h>
#include <assert.h>
#include <limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#ifndef be64toh
    #include <byteswap.h>
    #if __BYTE_ORDER == __LITTLE_ENDIAN
        #define be64toh(x) __bswap_64(x)
    #else
        #define be64toh(x) (x)
    #endif
#endif

using namespace std;

/** Print tool usage */
void print_usage();

/** Prepend to a path the img/ subdirectory.
 *
 *  @param[in,out] io_path - The path to modify / prepend to.
 */
void add_image_subdir(string& io_path);

/** Parse the image.modinfo file.
 *
 *  @param[in] i_image - The path to the image to parse the corresponding
 *                       modinfo.
 */
void parse_modinfo_file(const string& i_image);

/** Read the symbols from a module.
 *
 *  @param[in] pair<string, uint64_t>* - Pair of <Path of module, offset >.
 *
 *  Parameters are passed as a (void*) to allow this function to be started
 *  as a thread.
 *
 *  @return Unused.
 */
void* read_module_symbols(void*);

    /** Module information parsed from modinfo.  <Module, Offset> */
vector<pair<string, uint64_t> > g_modules;

    /** Name / path of the base image. */
string g_imageName;
    /** Name / path of the extended image. */
string g_extImageName;
    /** Pointer to the mmap of the base image. */
const char* g_imageFile;
    /** Size of the base image file. */
size_t g_imageFileSize;
    /** Pointer to the mmap of the extended image. */
const char* g_extImageFile;
    /** Size of the extended image file. */
size_t g_extImageFileSize;
    /** Offset (in memory) that the extended image is to be loaded at. */
uint64_t g_extImageOffset = ULONG_MAX;

    /** Cached value of the CROSS_PREFIX environment variable, used to
     *  call binutils tools. */
char* g_crossPrefix = NULL;

    /** Resulting symbol addresses and names.
     *
     *  This is a multimap because there are some symbol addresses with
     *  multiple names.  Ex. the data_start_address often collides with
     *  a global symbol in the data section.
     */
multimap<uint64_t, string> g_symbols;
    /** Mutex to protect symbol map. */
pthread_mutex_t g_symbolMutex = PTHREAD_MUTEX_INITIALIZER;

int main(int argc, char** argv)
{
    // Allow one argument (base image) or three arguments (base, extend, offset)
    if ((argc != 2) && (argc != 4))
    {
        print_usage();
    }

    // Get base image name.
    g_imageName = argv[1];
    add_image_subdir(g_imageName);

    // Get extended image name.
    if (argc > 3)
    {
        g_extImageName = argv[2];
        add_image_subdir(g_extImageName);

        // Read extended image offset from options.
        if (1 != sscanf(argv[3], "%lx", &g_extImageOffset))
        {
            print_usage();
        }
    }

    // Open base image.
    int base_fd = open(g_imageName.c_str(), O_RDONLY);
    if (-1 == base_fd)
    {
        printf("Failed to open image file: %s.\n", g_imageName.c_str());
        exit(-1);
    }
    struct stat base_stat;
    if (0 != fstat(base_fd, &base_stat))
    {
        printf("Failed to stat image file: %s.\n", g_imageName.c_str());
        exit(-1);
    }
    g_imageFileSize = base_stat.st_size;
    g_imageFile = (const char*) mmap(NULL, base_stat.st_size,
                                     PROT_READ, MAP_PRIVATE,
                                     base_fd, 0);

    // Open extended image.
    if (string() != g_extImageName.c_str())
    {
        int ext_fd = open(g_extImageName.c_str(), O_RDONLY);
        if (-1 == ext_fd)
        {
            printf("Failed to open image file: %s.\n", g_extImageName.c_str());
            exit(-1);
        }
        struct stat ext_stat;
        if (0 != fstat(ext_fd, &ext_stat))
        {
            printf("Failed to stat image file: %s.\n", g_extImageName.c_str());
            exit(-1);
        }
        g_extImageFileSize = ext_stat.st_size;
        g_extImageFile = (const char*) mmap(NULL, ext_stat.st_size,
                                            PROT_READ, MAP_PRIVATE,
                                            ext_fd, 0);
    }

    // Read CROSS_PREFIX environment variable.
    g_crossPrefix = getenv("CROSS_PREFIX");
    if (NULL == g_crossPrefix)
    {
        printf("Environment variable CROSS_PREFIX not set.\n");
        exit(-1);
    }
    g_crossPrefix = strdup(g_crossPrefix);

    // Parse modinfo file for base image.
    parse_modinfo_file(g_imageName);

    // Create threads for each ELF object in the image(s) to get their symbol
    // information.
    vector<pthread_t*> threads;
    for(vector<pair<string, uint64_t> >::const_iterator i = g_modules.begin();
        i != g_modules.end(); ++i)
    {
        const string& m = i->first;
        // Filter out non-ELF files by filename.
        if (strstr(m.c_str(), ".o") || strstr(m.c_str(), ".elf") ||
            strstr(m.c_str(), ".so"))
        {
            pthread_t* thread = new pthread_t;
            pthread_create(thread, NULL, read_module_symbols,
                           new pair<string,uint64_t>(*i));
            threads.push_back(thread);
        }
    }

    // Wait for all threads to finish.
    for(vector<pthread_t*>::const_iterator i = threads.begin();
        i != threads.end(); ++i)
    {
        pthread_join(*(*i), NULL);
    }

    // Output (in order) each symbol information.
    for (multimap<uint64_t, string>::const_iterator i = g_symbols.begin();
         i != g_symbols.end(); ++i)
    {
        printf("%s", i->second.c_str());
    }

    return 0;
}

void print_usage()
{
    printf("gensyms <image> [<extimage> <extoffset>]\n");
    exit(-1);
}

void add_image_subdir(string& io_path)
{
    // Prepend ./img if the path to the image directory is not already part
    // of the path.
    if (string::npos == io_path.find("img"))
    {
        io_path.insert(0, "./img/");
    }
}

void parse_modinfo_file(const string& i_image)
{
    // Open modinfo file.
    string modinfo_name = i_image + ".modinfo";
    FILE* modinfo_file = fopen(modinfo_name.c_str(), "r");
    if (NULL == modinfo_file)
    {
        printf("Unable to open modinfo file.\n");
        exit(-1);
    }

    // Parse one line at a time.
    char line[1024];
    do
    {
        // fgets returns NULL when no additional lines are present, break.
        if (NULL == fgets(line, 1024, modinfo_file)) break;

        // Lines should be formatted: "object,offset\n"

        // Skip lines without a comma.
        char* comma = strchr(line, ',');
        if (NULL == comma) continue;

        // Extract module name (everything before comma).
        string mod_name(line, comma - line);

        // Parse module offset (hex integer after comma).
        uint64_t mod_addr;
        if (1 != sscanf(comma+1, "0x%lx", &mod_addr)) continue;

        // Add to the module list.
        g_modules.push_back(make_pair(mod_name, mod_addr));

    } while(1);
}

void* read_module_symbols(void* input)
{
    // Get module name and offset from input parameter.
    pair<string, uint64_t>* mod_info =
        reinterpret_cast<pair<string,uint64_t>*>(input);
    const string& module = mod_info->first;
    uint64_t addr = mod_info->second;

    // Determine the full path to the module based on the base image path.
    // Assumes they are in the same subdirectory.
    string module_path = g_imageName.substr(0, g_imageName.rfind('/') + 1) +
                         module;

    // Create the 'objdump' command for finding all the symbols and start as
    // a sub-process.
    string command = string(g_crossPrefix) + string("objdump --syms -C ") +
                     module_path;
    FILE* pipe = popen(command.c_str(), "r");
    if (NULL == pipe) return NULL;

    // Local symbol map (to reduce contention on the global symbol map).
    //   No need to use the overhead of a map because we don't care about
    //   order at this point.
    vector<pair<uint64_t, string> > l_symbols;

    // Parse each line of the 'objdump' output.
    char line[1024];
    do
    {
        if (NULL == fgets(line, 1024, pipe)) break;

        size_t linelen = strlen(line);

        // Skip absolute values (ex. constants) and undefined symbols.
        if (strstr(line, "*ABS*") || strstr(line, "*UND*")) continue;
        // Skip section symbols (marked by 'd' in the 22nd column).
        if (linelen > 22 && 'd' == line[22]) continue;

        // First part of an objdump line is the symbol address, parse that.
        uint64_t line_address;
        if (1 != sscanf(line, "%16lx", &line_address)) continue;
        line_address += addr;

        // Determine if the symbol is a function and if it is in the .rodata
        // section.  Symbols in the .rodata section have a slightly longer
        // line than those in the .text/.data sections (by 2 characters).
        bool is_function = (linelen > 23 && 'F' == line[23]);
        size_t rodata = (NULL != strstr(line, ".rodata")) ? 2 : 0;

        // Parse the symbol size.
        uint64_t symbol_size;
        if (linelen > 32+rodata &&
            1 != sscanf(&line[32+rodata], "%lx", &symbol_size)) continue;

        // Parse the function name.
        assert(linelen > 48+rodata);
        string function = &line[48+rodata];
        function.resize(function.length() - 1); // remove the newline.

        // Function have two addresses: TOC entry and code address.  Objdump
        // gives the TOC entry, so we need to read the file itself to determine
        // the code address.  The first part of the TOC entry is the code
        // address.
        uint64_t code_addr = 0;
        if (is_function)
        {
            // Module is in the extended image, read from it.
            if (line_address > g_extImageOffset)
            {
                // Read code address.
                assert((line_address - g_extImageOffset) < g_extImageFileSize);
                memcpy(&code_addr,
                       &g_extImageFile[line_address - g_extImageOffset], 8);
            }
            // Module is in the base image.
            else
            {
                // Read code address.
                assert(line_address < g_imageFileSize);
                memcpy(&code_addr, &g_imageFile[line_address], 8);
            }
            // Fix up the endianness.
            code_addr = be64toh(code_addr);

            std::swap(code_addr, line_address);
        }

        // Print all of this into a new line and add to the symbol map.
        sprintf(line, "%c,%08lx,%08lx,%08lx,%s\n",
            is_function ? 'F' : 'V',
            line_address, code_addr, symbol_size,
            function.c_str());

        l_symbols.push_back(make_pair(line_address, line));

    } while(1);

    // Close subprocess (done).
    pclose(pipe);

    // Copy our local symbol list all at once into the global symbol list.
    pthread_mutex_lock(&g_symbolMutex);
    g_symbols.insert(l_symbols.begin(), l_symbols.end());
    pthread_mutex_unlock(&g_symbolMutex);

    return NULL;
}
<commit_msg>linker/gensyms: use stderr for displaying error messages<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/build/linker/gensyms.C $                                  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2013,2015                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#include <string>
#include <stdint.h>
#include <cstring>
#include <endian.h>
#include <assert.h>
#include <limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#ifndef be64toh
    #include <byteswap.h>
    #if __BYTE_ORDER == __LITTLE_ENDIAN
        #define be64toh(x) __bswap_64(x)
    #else
        #define be64toh(x) (x)
    #endif
#endif

using namespace std;

/** Print tool usage */
void print_usage();

/** Prepend to a path the img/ subdirectory.
 *
 *  @param[in,out] io_path - The path to modify / prepend to.
 */
void add_image_subdir(string& io_path);

/** Parse the image.modinfo file.
 *
 *  @param[in] i_image - The path to the image to parse the corresponding
 *                       modinfo.
 */
void parse_modinfo_file(const string& i_image);

/** Read the symbols from a module.
 *
 *  @param[in] pair<string, uint64_t>* - Pair of <Path of module, offset >.
 *
 *  Parameters are passed as a (void*) to allow this function to be started
 *  as a thread.
 *
 *  @return Unused.
 */
void* read_module_symbols(void*);

    /** Module information parsed from modinfo.  <Module, Offset> */
vector<pair<string, uint64_t> > g_modules;

    /** Name / path of the base image. */
string g_imageName;
    /** Name / path of the extended image. */
string g_extImageName;
    /** Pointer to the mmap of the base image. */
const char* g_imageFile;
    /** Size of the base image file. */
size_t g_imageFileSize;
    /** Pointer to the mmap of the extended image. */
const char* g_extImageFile;
    /** Size of the extended image file. */
size_t g_extImageFileSize;
    /** Offset (in memory) that the extended image is to be loaded at. */
uint64_t g_extImageOffset = ULONG_MAX;

    /** Cached value of the CROSS_PREFIX environment variable, used to
     *  call binutils tools. */
char* g_crossPrefix = NULL;

    /** Resulting symbol addresses and names.
     *
     *  This is a multimap because there are some symbol addresses with
     *  multiple names.  Ex. the data_start_address often collides with
     *  a global symbol in the data section.
     */
multimap<uint64_t, string> g_symbols;
    /** Mutex to protect symbol map. */
pthread_mutex_t g_symbolMutex = PTHREAD_MUTEX_INITIALIZER;

int main(int argc, char** argv)
{
    // Allow one argument (base image) or three arguments (base, extend, offset)
    if ((argc != 2) && (argc != 4))
    {
        print_usage();
    }

    // Get base image name.
    g_imageName = argv[1];
    add_image_subdir(g_imageName);

    // Get extended image name.
    if (argc > 3)
    {
        g_extImageName = argv[2];
        add_image_subdir(g_extImageName);

        // Read extended image offset from options.
        if (1 != sscanf(argv[3], "%lx", &g_extImageOffset))
        {
            print_usage();
        }
    }

    // Open base image.
    int base_fd = open(g_imageName.c_str(), O_RDONLY);
    if (-1 == base_fd)
    {
        fprintf(stderr, "Failed to open image file: %s.\n", g_imageName.c_str());
        exit(-1);
    }
    struct stat base_stat;
    if (0 != fstat(base_fd, &base_stat))
    {
        fprintf(stderr, "Failed to stat image file: %s.\n", g_imageName.c_str());
        exit(-1);
    }
    g_imageFileSize = base_stat.st_size;
    g_imageFile = (const char*) mmap(NULL, base_stat.st_size,
                                     PROT_READ, MAP_PRIVATE,
                                     base_fd, 0);

    // Open extended image.
    if (string() != g_extImageName.c_str())
    {
        int ext_fd = open(g_extImageName.c_str(), O_RDONLY);
        if (-1 == ext_fd)
        {
            fprintf(stderr, "Failed to open image file: %s.\n", g_extImageName.c_str());
            exit(-1);
        }
        struct stat ext_stat;
        if (0 != fstat(ext_fd, &ext_stat))
        {
            fprintf(stderr, "Failed to stat image file: %s.\n", g_extImageName.c_str());
            exit(-1);
        }
        g_extImageFileSize = ext_stat.st_size;
        g_extImageFile = (const char*) mmap(NULL, ext_stat.st_size,
                                            PROT_READ, MAP_PRIVATE,
                                            ext_fd, 0);
    }

    // Read CROSS_PREFIX environment variable.
    g_crossPrefix = getenv("CROSS_PREFIX");
    if (NULL == g_crossPrefix)
    {
        fprintf(stderr, "Environment variable CROSS_PREFIX not set.\n");
        exit(-1);
    }
    g_crossPrefix = strdup(g_crossPrefix);

    // Parse modinfo file for base image.
    parse_modinfo_file(g_imageName);

    // Create threads for each ELF object in the image(s) to get their symbol
    // information.
    vector<pthread_t*> threads;
    for(vector<pair<string, uint64_t> >::const_iterator i = g_modules.begin();
        i != g_modules.end(); ++i)
    {
        const string& m = i->first;
        // Filter out non-ELF files by filename.
        if (strstr(m.c_str(), ".o") || strstr(m.c_str(), ".elf") ||
            strstr(m.c_str(), ".so"))
        {
            pthread_t* thread = new pthread_t;
            pthread_create(thread, NULL, read_module_symbols,
                           new pair<string,uint64_t>(*i));
            threads.push_back(thread);
        }
    }

    // Wait for all threads to finish.
    for(vector<pthread_t*>::const_iterator i = threads.begin();
        i != threads.end(); ++i)
    {
        pthread_join(*(*i), NULL);
    }

    // Output (in order) each symbol information.
    for (multimap<uint64_t, string>::const_iterator i = g_symbols.begin();
         i != g_symbols.end(); ++i)
    {
        printf("%s", i->second.c_str());
    }

    return 0;
}

void print_usage()
{
    fprintf(stderr, "gensyms <image> [<extimage> <extoffset>]\n");
    exit(-1);
}

void add_image_subdir(string& io_path)
{
    // Prepend ./img if the path to the image directory is not already part
    // of the path.
    if (string::npos == io_path.find("img"))
    {
        io_path.insert(0, "./img/");
    }
}

void parse_modinfo_file(const string& i_image)
{
    // Open modinfo file.
    string modinfo_name = i_image + ".modinfo";
    FILE* modinfo_file = fopen(modinfo_name.c_str(), "r");
    if (NULL == modinfo_file)
    {
        fprintf(stderr, "Unable to open modinfo file.\n");
        exit(-1);
    }

    // Parse one line at a time.
    char line[1024];
    do
    {
        // fgets returns NULL when no additional lines are present, break.
        if (NULL == fgets(line, 1024, modinfo_file)) break;

        // Lines should be formatted: "object,offset\n"

        // Skip lines without a comma.
        char* comma = strchr(line, ',');
        if (NULL == comma) continue;

        // Extract module name (everything before comma).
        string mod_name(line, comma - line);

        // Parse module offset (hex integer after comma).
        uint64_t mod_addr;
        if (1 != sscanf(comma+1, "0x%lx", &mod_addr)) continue;

        // Add to the module list.
        g_modules.push_back(make_pair(mod_name, mod_addr));

    } while(1);
}

void* read_module_symbols(void* input)
{
    // Get module name and offset from input parameter.
    pair<string, uint64_t>* mod_info =
        reinterpret_cast<pair<string,uint64_t>*>(input);
    const string& module = mod_info->first;
    uint64_t addr = mod_info->second;

    // Determine the full path to the module based on the base image path.
    // Assumes they are in the same subdirectory.
    string module_path = g_imageName.substr(0, g_imageName.rfind('/') + 1) +
                         module;

    // Create the 'objdump' command for finding all the symbols and start as
    // a sub-process.
    string command = string(g_crossPrefix) + string("objdump --syms -C ") +
                     module_path;
    FILE* pipe = popen(command.c_str(), "r");
    if (NULL == pipe) return NULL;

    // Local symbol map (to reduce contention on the global symbol map).
    //   No need to use the overhead of a map because we don't care about
    //   order at this point.
    vector<pair<uint64_t, string> > l_symbols;

    // Parse each line of the 'objdump' output.
    char line[1024];
    do
    {
        if (NULL == fgets(line, 1024, pipe)) break;

        size_t linelen = strlen(line);

        // Skip absolute values (ex. constants) and undefined symbols.
        if (strstr(line, "*ABS*") || strstr(line, "*UND*")) continue;
        // Skip section symbols (marked by 'd' in the 22nd column).
        if (linelen > 22 && 'd' == line[22]) continue;

        // First part of an objdump line is the symbol address, parse that.
        uint64_t line_address;
        if (1 != sscanf(line, "%16lx", &line_address)) continue;
        line_address += addr;

        // Determine if the symbol is a function and if it is in the .rodata
        // section.  Symbols in the .rodata section have a slightly longer
        // line than those in the .text/.data sections (by 2 characters).
        bool is_function = (linelen > 23 && 'F' == line[23]);
        size_t rodata = (NULL != strstr(line, ".rodata")) ? 2 : 0;

        // Parse the symbol size.
        uint64_t symbol_size;
        if (linelen > 32+rodata &&
            1 != sscanf(&line[32+rodata], "%lx", &symbol_size)) continue;

        // Parse the function name.
        assert(linelen > 48+rodata);
        string function = &line[48+rodata];
        function.resize(function.length() - 1); // remove the newline.

        // Function have two addresses: TOC entry and code address.  Objdump
        // gives the TOC entry, so we need to read the file itself to determine
        // the code address.  The first part of the TOC entry is the code
        // address.
        uint64_t code_addr = 0;
        if (is_function)
        {
            // Module is in the extended image, read from it.
            if (line_address > g_extImageOffset)
            {
                // Read code address.
                assert((line_address - g_extImageOffset) < g_extImageFileSize);
                memcpy(&code_addr,
                       &g_extImageFile[line_address - g_extImageOffset], 8);
            }
            // Module is in the base image.
            else
            {
                // Read code address.
                assert(line_address < g_imageFileSize);
                memcpy(&code_addr, &g_imageFile[line_address], 8);
            }
            // Fix up the endianness.
            code_addr = be64toh(code_addr);

            std::swap(code_addr, line_address);
        }

        // Print all of this into a new line and add to the symbol map.
        sprintf(line, "%c,%08lx,%08lx,%08lx,%s\n",
            is_function ? 'F' : 'V',
            line_address, code_addr, symbol_size,
            function.c_str());

        l_symbols.push_back(make_pair(line_address, line));

    } while(1);

    // Close subprocess (done).
    pclose(pipe);

    // Copy our local symbol list all at once into the global symbol list.
    pthread_mutex_lock(&g_symbolMutex);
    g_symbols.insert(l_symbols.begin(), l_symbols.end());
    pthread_mutex_unlock(&g_symbolMutex);

    return NULL;
}
<|endoftext|>


<commit_before>
// Includes
#include "Logger.h"

// STD.
#include <iostream>

Logger &Logger::instance()
{
    static Logger logger;
    return logger;
}

void Logger::logMessage(const std::string &message)
{
    fprintf(stdout, "%s\n", message.c_str());

    std::vector<Delegate*>::iterator iter;
    for (iter = delegates_.begin(); iter != delegates_.end(); ++iter)
    {
        (*iter)->logMessage(message);
    }
}

void Logger::logError(const std::string &message)
{
    fprintf(stderr, "%s\n", message.c_str());

    std::vector<Delegate*>::iterator iter;
    for (iter = delegates_.begin(); iter != delegates_.end(); ++iter)
    {
        (*iter)->logError(message);
    }
}

void Logger::addDelegate(Logger::Delegate *delegate)
{
    if (delegate != nullptr)
    {
        delegates_.push_back(delegate);
    }
}

void Logger::removeDelegate(Logger::Delegate *delegate)
{
    if (delegate != nullptr)
    {
        delegates_.push_back(delegate);
    }
}

Logger::Logger()
{
}
<commit_msg>Fix implementation of removeDelegate.<commit_after>
// Includes
#include "Logger.h"

// STD.
#include <iostream>

Logger &Logger::instance()
{
    static Logger logger;
    return logger;
}

void Logger::logMessage(const std::string &message)
{
    fprintf(stdout, "%s\n", message.c_str());

    std::vector<Delegate*>::iterator iter;
    for (iter = delegates_.begin(); iter != delegates_.end(); ++iter)
    {
        (*iter)->logMessage(message);
    }
}

void Logger::logError(const std::string &message)
{
    fprintf(stderr, "%s\n", message.c_str());

    std::vector<Delegate*>::iterator iter;
    for (iter = delegates_.begin(); iter != delegates_.end(); ++iter)
    {
        (*iter)->logError(message);
    }
}

void Logger::addDelegate(Logger::Delegate *delegate)
{
    if (delegate != nullptr)
    {
        delegates_.push_back(delegate);
    }
}

void Logger::removeDelegate(Logger::Delegate *delegate)
{
    if (delegate != nullptr)
    {
        delegates_.erase(std::find(delegates_.begin(), delegates_.end(), delegate));
    }
}

Logger::Logger()
{
}
<|endoftext|>


<commit_before>#include "Planner.h"
#include <algorithm>

Node::Node(Vec3i coordinates_, Node *Parent_) {
  Parent = Parent_;
  coordinates = coordinates_;
  G = H = 0;
}

double Node::Get_Score() {
  return G + H;
}

bool Vec3i::operator ==(const Vec3i& coordinates_) {
  return (x == coordinates_.x && y == coordinates_.y && z == coordinates_.z);
}

Vec3i operator +(const Vec3i& left_, const Vec3i& right_) {
  return {left_.x + right_.x, left_.y + right_.y,left_.z + right_.z};
}

Planner::Planner() {
  Set_Heuristic(&Heuristic::Euclidean);
  direction = {
    { 0,0,1}, {0,1,0}, {1,0,0}, {0,0,-1}, {0,-1,0}, {-1,0,0}, {0,1,1}, {1,0,1}, {1,1,0},
    { 0,-1,-1}, {-1,0,-1}, {-1,-1,0},
    { 0,1,-1}, {0,-1,1}, {1,0,-1}, {-1,0,1}, {1,-1,0}, {-1,1,0}, {1,1,-1}, {1,-1,1},
    { -1,1,1}, {1,-1,-1}, {-1,-1,1}, {-1,1,-1}, {1,1,1}, {-1,-1,-1}
  };
}

void Planner::Set_World_Size(Vec3i World_Size_) {
  World_Size = World_Size_;
}

void Planner::Set_Heuristic(std::function<double(Vec3i, Vec3i)> heuristic_) {
  heuristic = std::bind(heuristic_, std::placeholders::_1,
                        std::placeholders::_2);
}

void Planner::Add_Collision(Vec3i coordinates_) {
  walls.push_back(coordinates_);
}

std::vector<Vec3i> Planner::findPath(Vec3i Now_, Vec3i Neighbor_) {
  Node *current = nullptr;
  std::set<Node*> Open_Set, Closed_Set;
  Open_Set.insert(new Node(Now_));

  while (!Open_Set.empty()) {
    current = *Open_Set.begin();
    for (auto node : Open_Set) {
      if (node->Get_Score() <= current->Get_Score()) {
        current = node;
      }
    }

    if (current->coordinates == Neighbor_) {
      break;
    }

    Closed_Set.insert(current);
    Open_Set.erase(std::find(Open_Set.begin(), Open_Set.end(), current));

    for (double i = 0; i < 26; ++i) {
      Vec3i newCoordinates(current->coordinates + direction[i]);
      if (Detect_Collision(newCoordinates)
          || Find_Node(Closed_Set, newCoordinates)) {
        continue;
      }

      double Total_Cost = current->G
          + ((i < 6) ? 100 : ((i > 5 && i < 18) ? 141 : 173));

      Node *successor = Find_Node(Open_Set, newCoordinates);
      if (successor == nullptr) {
        successor = new Node(newCoordinates, current);
        successor->G = Total_Cost;
        successor->H = heuristic(successor->coordinates, Neighbor_);
        Open_Set.insert(successor);
      } else if (Total_Cost < successor->G) {
        successor->Parent = current;
        successor->G = Total_Cost;
      }
    }
  }

  std::vector<Vec3i> path;
  while (current != nullptr) {
    path.push_back(current->coordinates);
    current = current->Parent;
  }

  return path;
}

Node* Planner::Find_Node(std::set<Node*>& nodes_, Vec3i coordinates_) {
  for (auto node : nodes_) {
    if (node->coordinates == coordinates_) {
      return node;
    }
  }
  return nullptr;
}

bool Planner::Detect_Collision(Vec3i coordinates_) {
  if (coordinates_.x < 0 || coordinates_.x >= World_Size.x || coordinates_.y < 0
      || coordinates_.y >= World_Size.y || coordinates_.z < 0
      || coordinates_.z >= World_Size.z
      || std::find(walls.begin(), walls.end(), coordinates_) != walls.end()) {
    return true;
  }
  return false;
}

Vec3i Heuristic::Distance(Vec3i Now_, Vec3i Neighbor_) {
  return {abs(Now_.x - Neighbor_.x), abs(Now_.y - Neighbor_.y),abs(Now_.z - Neighbor_.z)};
}

double Heuristic::Euclidean(Vec3i Now_, Vec3i Neighbor_) {
  auto delta = std::move(Distance(Now_, Neighbor_));
  return static_cast<double>(100
      * sqrt(pow(delta.x, 2) + pow(delta.y, 2) + pow(delta.z, 2)));
}

<commit_msg>Fixed the header files Inclusion Error which were causing Power & sqrt operations to fail<commit_after>#include "Planner.h"
#include <algorithm>
#include <cmath>

Node::Node(Vec3i coordinates_, Node *Parent_) {
  Parent = Parent_;
  coordinates = coordinates_;
  G = H = 0;
}

double Node::Get_Score() {
  return G + H;
}

bool Vec3i::operator ==(const Vec3i& coordinates_) {
  return (x == coordinates_.x && y == coordinates_.y && z == coordinates_.z);
}

Vec3i operator +(const Vec3i& left_, const Vec3i& right_) {
  return {left_.x + right_.x, left_.y + right_.y,left_.z + right_.z};
}

Planner::Planner() {
  Set_Heuristic(&Heuristic::Euclidean);
  direction = {
    { 0,0,1}, {0,1,0}, {1,0,0}, {0,0,-1}, {0,-1,0}, {-1,0,0}, {0,1,1}, {1,0,1}, {1,1,0},
    { 0,-1,-1}, {-1,0,-1}, {-1,-1,0},
    { 0,1,-1}, {0,-1,1}, {1,0,-1}, {-1,0,1}, {1,-1,0}, {-1,1,0}, {1,1,-1}, {1,-1,1},
    { -1,1,1}, {1,-1,-1}, {-1,-1,1}, {-1,1,-1}, {1,1,1}, {-1,-1,-1}
  };
}

void Planner::Set_World_Size(Vec3i World_Size_) {
  World_Size = World_Size_;
}

void Planner::Set_Heuristic(std::function<double(Vec3i, Vec3i)> heuristic_) {
  heuristic = std::bind(heuristic_, std::placeholders::_1,
                        std::placeholders::_2);
}

void Planner::Add_Collision(Vec3i coordinates_) {
  walls.push_back(coordinates_);
}

std::vector<Vec3i> Planner::findPath(Vec3i Now_, Vec3i Neighbor_) {
  Node *current = nullptr;
  std::set<Node*> Open_Set, Closed_Set;
  Open_Set.insert(new Node(Now_));

  while (!Open_Set.empty()) {
    current = *Open_Set.begin();
    for (auto node : Open_Set) {
      if (node->Get_Score() <= current->Get_Score()) {
        current = node;
      }
    }

    if (current->coordinates == Neighbor_) {
      break;
    }

    Closed_Set.insert(current);
    Open_Set.erase(std::find(Open_Set.begin(), Open_Set.end(), current));

    for (double i = 0; i < 26; ++i) {
      Vec3i newCoordinates(current->coordinates + direction[i]);
      if (Detect_Collision(newCoordinates)
          || Find_Node(Closed_Set, newCoordinates)) {
        continue;
      }

      double Total_Cost = current->G
          + ((i < 6) ? 100 : ((i > 5 && i < 18) ? 141 : 173));

      Node *successor = Find_Node(Open_Set, newCoordinates);
      if (successor == nullptr) {
        successor = new Node(newCoordinates, current);
        successor->G = Total_Cost;
        successor->H = heuristic(successor->coordinates, Neighbor_);
        Open_Set.insert(successor);
      } else if (Total_Cost < successor->G) {
        successor->Parent = current;
        successor->G = Total_Cost;
      }
    }
  }

  std::vector<Vec3i> path;
  while (current != nullptr) {
    path.push_back(current->coordinates);
    current = current->Parent;
  }

  return path;
}

Node* Planner::Find_Node(std::set<Node*>& nodes_, Vec3i coordinates_) {
  for (auto node : nodes_) {
    if (node->coordinates == coordinates_) {
      return node;
    }
  }
  return nullptr;
}

bool Planner::Detect_Collision(Vec3i coordinates_) {
  if (coordinates_.x < 0 || coordinates_.x >= World_Size.x || coordinates_.y < 0
      || coordinates_.y >= World_Size.y || coordinates_.z < 0
      || coordinates_.z >= World_Size.z
      || std::find(walls.begin(), walls.end(), coordinates_) != walls.end()) {
    return true;
  }
  return false;
}

Vec3i Heuristic::Distance(Vec3i Now_, Vec3i Neighbor_) {
  return {abs(Now_.x - Neighbor_.x), abs(Now_.y - Neighbor_.y),abs(Now_.z - Neighbor_.z)};
}

double Heuristic::Euclidean(Vec3i Now_, Vec3i Neighbor_) {
  auto delta = std::move(Distance(Now_, Neighbor_));
  return static_cast<double>(100
      * sqrt(pow(delta.x, 2) + pow(delta.y, 2) + pow(delta.z, 2)));
}

<|endoftext|>


<commit_before>#include "TextDrawer.hpp"
#include "Font.hpp"
#include "Texture.hpp"
#include "UniformBuffer.hpp"
#include "VertexBuffer.hpp"
#include "IndexBuffer.hpp"
#include "VertexShader.hpp"
#include "PixelShader.hpp"
#include "BlendState.hpp"
#include "SamplerState.hpp"
#include "Device.hpp"
#include "Context.hpp"
#include "ShaderCache.hpp"
#include "VertexLayout.hpp"
#include "VertexLayoutElement.hpp"
#include "AttributeLayout.hpp"
#include "AttributeLayoutSlot.hpp"
#include "AttributeLayoutElement.hpp"
#include "AttributeBinding.hpp"
#include "RenderBuffer.hpp"
#include "DepthStencilBuffer.hpp"
#include "../MemoryFile.hpp"
#include "../StringTraveler.hpp"
#include "../Exception.hpp"
#include "../inanity-shaders.hpp"

BEGIN_INANITY_GRAPHICS

using namespace Shaders;

/// Вспомогательная структура для рисователя.
struct TextDrawerHelper : public Object
{
	/// Максимальное количество символов, рисуемое за раз.
	static const int maxSymbolsCount = 64;

	ptr<VertexLayout> vl;
	ptr<VertexLayoutElement> vlePosition;
	ptr<AttributeLayout> al;
	ptr<AttributeLayoutSlot> als;
	ptr<AttributeLayoutElement> alePosition;
	ptr<AttributeBinding> ab;

	Value<vec4> aCorner;

	Interpolant<vec2> iTexcoord;
	Interpolant<vec4> iColor;

	ptr<UniformGroup> ugSymbols;
	/// Координаты символов на экране.
	UniformArray<vec4> uPositions;
	/// Текстурные координаты символов.
	UniformArray<vec4> uTexcoords;
	/// Цвета символов.
	UniformArray<vec4> uColors;

	/// Текстура шрифта.
	/** Задаёт альфу для шрифта. */
	Sampler<float, 2> uFontSampler;
	/// Sampler state.
	ptr<SamplerState> ss;

	ptr<VertexBuffer> vb;
	ptr<VertexShader> vs;
	ptr<PixelShader> ps;
	ptr<BlendState> bs;

	TextDrawerHelper(ptr<Device> device, ptr<ShaderCache> shaderCache) :
		vl(NEW(VertexLayout(sizeof(vec4)))),
		vlePosition(vl->AddElement(DataTypes::_vec4, 0)),
		al(NEW(AttributeLayout())),
		als(al->AddSlot()),
		alePosition(al->AddElement(als, vlePosition)),
		ab(device->CreateAttributeBinding(al)),

		aCorner(alePosition),

		iTexcoord(1),
		iColor(2),

		ugSymbols(NEW(UniformGroup(0))),
		uPositions(ugSymbols->AddUniformArray<vec4>(maxSymbolsCount)),
		uTexcoords(ugSymbols->AddUniformArray<vec4>(maxSymbolsCount)),
		uColors(ugSymbols->AddUniformArray<vec4>(maxSymbolsCount)),

		uFontSampler(0)
	{
		try
		{
			ugSymbols->Finalize(device);

			// создать геометрию
			static const vec4 vertices[6] =
			{
				vec4(0, 1, 1, 0),
				vec4(1, 1, 0, 0),
				vec4(1, 0, 0, 1),
				vec4(0, 1, 1, 0),
				vec4(1, 0, 0, 1),
				vec4(0, 0, 1, 1)
			};

			vb = device->CreateStaticVertexBuffer(MemoryFile::CreateViaCopy(vertices, sizeof(vertices)), vl);

			// вершинный шейдер
			Temp<uint> tmpInstance;
			Temp<vec4> tmpPosition, tmpTexcoord, tmpColor;
			vs = shaderCache->GetVertexShader((
				tmpInstance = getInstanceID(),

				tmpPosition = uPositions[tmpInstance],
				tmpTexcoord = uTexcoords[tmpInstance],
				tmpColor = uColors[tmpInstance],

				setPosition(newvec4(
					dot(aCorner["xz"], tmpPosition["xz"]),
					dot(aCorner["yw"], tmpPosition["yw"]),
					0, 1)),
				iTexcoord = newvec2(
					dot(aCorner["xz"], tmpTexcoord["xz"]),
					dot(aCorner["yw"], tmpTexcoord["yw"])),
				iColor = tmpColor
			));

			// пиксельный шейдер
			ps = shaderCache->GetPixelShader((
				iTexcoord,
				iColor,

				fragment(0, newvec4(iColor["xyz"], iColor["w"] * uFontSampler.Sample(iTexcoord)))
			));

			// настройки смешивания
			bs = device->CreateBlendState();
			bs->SetColor(BlendState::colorSourceSrcAlpha, BlendState::colorSourceInvSrcAlpha, BlendState::operationAdd);

			// настройки семплирования для шрифта
			ss = device->CreateSamplerState();
			ss->SetFilter(SamplerState::filterLinear, SamplerState::filterLinear, SamplerState::filterLinear);
			ss->SetWrap(SamplerState::wrapBorder, SamplerState::wrapBorder, SamplerState::wrapBorder);
			float color[] = { 0, 0, 0, 0 };
			ss->SetBorderColor(color);
		}
		catch(Exception* exception)
		{
			THROW_SECONDARY("Can't create text drawer helper", exception);
		}
	}
};

TextDrawer::TextDrawer(ptr<TextDrawerHelper> helper)
: helper(helper), queuedCharsCount(0) {}

void TextDrawer::Prepare(ptr<Context> context, int viewportWidth, int viewportHeight)
{
	this->context = context;

	// сбросить текущий шрифт и текстуру
	currentFont = 0;
	currentFontTexture = 0;

	// вычислить масштабирование
	scaleX = 2.0f / viewportWidth;
	scaleY = 2.0f / viewportHeight;
}

void TextDrawer::SetFont(ptr<Font> font)
{
	// запомнить шрифт
	currentFont = font;
	// если текстура поменялась
	ptr<Texture> texture = font->GetTexture();
	if(texture != currentFontTexture)
	{
		// сбросить очередь
		Flush();
		// запомнить новую текстуру
		currentFontTexture = texture;
	}
}

void TextDrawer::DrawSymbol(const vec4& position, const vec4& texcoord, const vec4& color)
{
	// если очередь переполнена
	if(queuedCharsCount >= TextDrawerHelper::maxSymbolsCount)
		// сбросить очередь
		Flush();

	// добавить символ в очередь
	helper->uPositions.SetValue(queuedCharsCount, position);
	helper->uTexcoords.SetValue(queuedCharsCount, texcoord);
	helper->uColors.SetValue(queuedCharsCount, color);
	++queuedCharsCount;
}

void TextDrawer::DrawTextLine(const String& text, float x, float y, const vec4& color, int alignment)
{
	Font* font = currentFont;

	//получить высоту символов
	float charHeight = font->GetCharHeight() * scaleY;

	//определить ширину строки
	float stringWidth = 0;
	{
		StringTraveler traveler(text);
		wchar_t symbol, lastSymbol = (wchar_t)-1;
		while(traveler.Next(symbol))
		{
			// если это не первый символ в строке
			if(lastSymbol != (wchar_t)-1)
				// добавить кернинг
				stringWidth += font->GetKerning(lastSymbol, symbol);
			// добавить ширину символа
			stringWidth += font->GetChar(symbol).width;
			// запомнить символ для следующей кернинг-пары
			lastSymbol = symbol;
		}
		// масштабирование
		stringWidth *= scaleX;
	}

	//определить высоту строки (пока просто - многострочный текст не поддерживается)
	float stringHeight = charHeight;

	//установить реальные x и y в соответствии с выравниванием
	//для FontAlignment::Left ничего не надо
	switch(alignment & FontAlignments::HorizontalMask)
	{
	case FontAlignments::Center:
		x -= stringWidth * 0.5f;
		break;
	case FontAlignments::Right:
		x -= stringWidth;
		break;
	}
	//для FontAlignment::Bottom ничего не надо
	switch(alignment & FontAlignments::VerticalMask)
	{
	case FontAlignments::Top:
		y -= stringHeight;
		break;
	case FontAlignments::Middle:
		y -= stringHeight * 0.5f;
		break;
	}

	//левая граница
	float left = x;

	//цикл обработки символов
	StringTraveler traveler(text);
	wchar_t symbol, lastSymbol = (wchar_t)-1;
	while(traveler.Next(symbol))
	{
		// если это не первый символ
		if(lastSymbol != (wchar_t)-1)
			// сдвинуть левую границу на кернинг
			left += font->GetKerning(lastSymbol, symbol) * scaleX;
		//получить символ
		const FontChar& fontChar = font->GetChar(symbol);
		//получить ширину символа
		float charWidth = fontChar.width * scaleX;

		// вывести символ
		DrawSymbol(
			vec4(
				left + fontChar.screenFirstUV.x * scaleX, y + fontChar.screenFirstUV.y * scaleY,
				left + fontChar.screenSecondUV.x * scaleX, y + fontChar.screenSecondUV.y * scaleY
			),
			vec4(fontChar.firstUV.x, fontChar.firstUV.y, fontChar.secondUV.x, fontChar.secondUV.y),
			color
		);

		//сдвинуть левую границу
		left += charWidth;

		// запомнить символ
		lastSymbol = symbol;
	}
}

void TextDrawer::Flush()
{
	// если очередь пуста, делать нечего
	if(!queuedCharsCount)
		return;

	Context::LetAttributeBinding lab(context, helper->ab);
	Context::LetVertexBuffer lvb(context, 0, helper->vb);
	Context::LetIndexBuffer lib(context, 0);
	Context::LetVertexShader lvs(context, helper->vs);
	Context::LetPixelShader lps(context, helper->ps);
	Context::LetBlendState lbs(context, helper->bs);
	Context::LetCullMode lcm(context, Context::cullModeNone);
	Context::LetFillMode lfm(context, Context::fillModeSolid);
	Context::LetDepthTestFunc ldtf(context, Context::depthTestFuncAlways);
	Context::LetDepthWrite ldw(context, false);
	Context::LetUniformBuffer lub(context, helper->ugSymbols);
	Context::LetSampler ls(context, helper->uFontSampler, currentFontTexture, helper->ss);

	// загрузить символы
	helper->ugSymbols->Upload(context);

	// нарисовать
	context->DrawInstanced(queuedCharsCount);

	// сбросить количество символов
	queuedCharsCount = 0;
}

ptr<TextDrawer> TextDrawer::Create(ptr<Device> device, ptr<ShaderCache> shaderCache)
{
	return NEW(TextDrawer(NEW(TextDrawerHelper(device, shaderCache))));
}

END_INANITY_GRAPHICS
<commit_msg>use instancer in TextDrawer<commit_after>#include "TextDrawer.hpp"
#include "Font.hpp"
#include "Texture.hpp"
#include "UniformBuffer.hpp"
#include "VertexBuffer.hpp"
#include "IndexBuffer.hpp"
#include "VertexShader.hpp"
#include "PixelShader.hpp"
#include "BlendState.hpp"
#include "SamplerState.hpp"
#include "Device.hpp"
#include "Context.hpp"
#include "ShaderCache.hpp"
#include "VertexLayout.hpp"
#include "VertexLayoutElement.hpp"
#include "AttributeLayout.hpp"
#include "AttributeLayoutSlot.hpp"
#include "AttributeLayoutElement.hpp"
#include "AttributeBinding.hpp"
#include "RenderBuffer.hpp"
#include "DepthStencilBuffer.hpp"
#include "../MemoryFile.hpp"
#include "../StringTraveler.hpp"
#include "../Exception.hpp"
#include "../inanity-shaders.hpp"

BEGIN_INANITY_GRAPHICS

using namespace Shaders;

/// Вспомогательная структура для рисователя.
struct TextDrawerHelper : public Object
{
	/// Максимальное количество символов, рисуемое за раз.
	static const int maxSymbolsCount = 64;

	ptr<VertexLayout> vl;
	ptr<VertexLayoutElement> vlePosition;
	ptr<AttributeLayout> al;
	ptr<AttributeLayoutSlot> als;
	ptr<AttributeLayoutElement> alePosition;
	ptr<Instancer> instancer;
	ptr<AttributeBinding> ab;

	Value<vec4> aCorner;

	Interpolant<vec2> iTexcoord;
	Interpolant<vec4> iColor;

	ptr<UniformGroup> ugSymbols;
	/// Координаты символов на экране.
	UniformArray<vec4> uPositions;
	/// Текстурные координаты символов.
	UniformArray<vec4> uTexcoords;
	/// Цвета символов.
	UniformArray<vec4> uColors;

	/// Текстура шрифта.
	/** Задаёт альфу для шрифта. */
	Sampler<float, 2> uFontSampler;
	/// Sampler state.
	ptr<SamplerState> ss;

	ptr<VertexBuffer> vb;
	ptr<VertexShader> vs;
	ptr<PixelShader> ps;
	ptr<BlendState> bs;

	TextDrawerHelper(ptr<Device> device, ptr<ShaderCache> shaderCache) :
		vl(NEW(VertexLayout(sizeof(vec4)))),
		vlePosition(vl->AddElement(DataTypes::_vec4, 0)),
		al(NEW(AttributeLayout())),
		als(al->AddSlot()),
		alePosition(al->AddElement(als, vlePosition)),
		instancer(NEW(Instancer(device, maxSymbolsCount, al))),
		ab(device->CreateAttributeBinding(al)),

		aCorner(alePosition),

		iTexcoord(1),
		iColor(2),

		ugSymbols(NEW(UniformGroup(0))),
		uPositions(ugSymbols->AddUniformArray<vec4>(maxSymbolsCount)),
		uTexcoords(ugSymbols->AddUniformArray<vec4>(maxSymbolsCount)),
		uColors(ugSymbols->AddUniformArray<vec4>(maxSymbolsCount)),

		uFontSampler(0)
	{
		try
		{
			ugSymbols->Finalize(device);

			// создать геометрию
			static const vec4 vertices[6] =
			{
				vec4(0, 1, 1, 0),
				vec4(1, 1, 0, 0),
				vec4(1, 0, 0, 1),
				vec4(0, 1, 1, 0),
				vec4(1, 0, 0, 1),
				vec4(0, 0, 1, 1)
			};

			vb = device->CreateStaticVertexBuffer(MemoryFile::CreateViaCopy(vertices, sizeof(vertices)), vl);

			// вершинный шейдер
			Temp<uint> tmpInstance;
			Temp<vec4> tmpPosition, tmpTexcoord, tmpColor;
			vs = shaderCache->GetVertexShader((
				tmpInstance = instancer->GetInstanceID(),

				tmpPosition = uPositions[tmpInstance],
				tmpTexcoord = uTexcoords[tmpInstance],
				tmpColor = uColors[tmpInstance],

				setPosition(newvec4(
					dot(aCorner["xz"], tmpPosition["xz"]),
					dot(aCorner["yw"], tmpPosition["yw"]),
					0, 1)),
				iTexcoord = newvec2(
					dot(aCorner["xz"], tmpTexcoord["xz"]),
					dot(aCorner["yw"], tmpTexcoord["yw"])),
				iColor = tmpColor
			));

			// пиксельный шейдер
			ps = shaderCache->GetPixelShader((
				iTexcoord,
				iColor,

				fragment(0, newvec4(iColor["xyz"], iColor["w"] * uFontSampler.Sample(iTexcoord)))
			));

			// настройки смешивания
			bs = device->CreateBlendState();
			bs->SetColor(BlendState::colorSourceSrcAlpha, BlendState::colorSourceInvSrcAlpha, BlendState::operationAdd);

			// настройки семплирования для шрифта
			ss = device->CreateSamplerState();
			ss->SetFilter(SamplerState::filterLinear, SamplerState::filterLinear, SamplerState::filterLinear);
			ss->SetWrap(SamplerState::wrapBorder, SamplerState::wrapBorder, SamplerState::wrapBorder);
			float color[] = { 0, 0, 0, 0 };
			ss->SetBorderColor(color);
		}
		catch(Exception* exception)
		{
			THROW_SECONDARY("Can't create text drawer helper", exception);
		}
	}
};

TextDrawer::TextDrawer(ptr<TextDrawerHelper> helper)
: helper(helper), queuedCharsCount(0) {}

void TextDrawer::Prepare(ptr<Context> context, int viewportWidth, int viewportHeight)
{
	this->context = context;

	// сбросить текущий шрифт и текстуру
	currentFont = 0;
	currentFontTexture = 0;

	// вычислить масштабирование
	scaleX = 2.0f / viewportWidth;
	scaleY = 2.0f / viewportHeight;
}

void TextDrawer::SetFont(ptr<Font> font)
{
	// запомнить шрифт
	currentFont = font;
	// если текстура поменялась
	ptr<Texture> texture = font->GetTexture();
	if(texture != currentFontTexture)
	{
		// сбросить очередь
		Flush();
		// запомнить новую текстуру
		currentFontTexture = texture;
	}
}

void TextDrawer::DrawSymbol(const vec4& position, const vec4& texcoord, const vec4& color)
{
	// если очередь переполнена
	if(queuedCharsCount >= TextDrawerHelper::maxSymbolsCount)
		// сбросить очередь
		Flush();

	// добавить символ в очередь
	helper->uPositions.SetValue(queuedCharsCount, position);
	helper->uTexcoords.SetValue(queuedCharsCount, texcoord);
	helper->uColors.SetValue(queuedCharsCount, color);
	++queuedCharsCount;
}

void TextDrawer::DrawTextLine(const String& text, float x, float y, const vec4& color, int alignment)
{
	Font* font = currentFont;

	//получить высоту символов
	float charHeight = font->GetCharHeight() * scaleY;

	//определить ширину строки
	float stringWidth = 0;
	{
		StringTraveler traveler(text);
		wchar_t symbol, lastSymbol = (wchar_t)-1;
		while(traveler.Next(symbol))
		{
			// если это не первый символ в строке
			if(lastSymbol != (wchar_t)-1)
				// добавить кернинг
				stringWidth += font->GetKerning(lastSymbol, symbol);
			// добавить ширину символа
			stringWidth += font->GetChar(symbol).width;
			// запомнить символ для следующей кернинг-пары
			lastSymbol = symbol;
		}
		// масштабирование
		stringWidth *= scaleX;
	}

	//определить высоту строки (пока просто - многострочный текст не поддерживается)
	float stringHeight = charHeight;

	//установить реальные x и y в соответствии с выравниванием
	//для FontAlignment::Left ничего не надо
	switch(alignment & FontAlignments::HorizontalMask)
	{
	case FontAlignments::Center:
		x -= stringWidth * 0.5f;
		break;
	case FontAlignments::Right:
		x -= stringWidth;
		break;
	}
	//для FontAlignment::Bottom ничего не надо
	switch(alignment & FontAlignments::VerticalMask)
	{
	case FontAlignments::Top:
		y -= stringHeight;
		break;
	case FontAlignments::Middle:
		y -= stringHeight * 0.5f;
		break;
	}

	//левая граница
	float left = x;

	//цикл обработки символов
	StringTraveler traveler(text);
	wchar_t symbol, lastSymbol = (wchar_t)-1;
	while(traveler.Next(symbol))
	{
		// если это не первый символ
		if(lastSymbol != (wchar_t)-1)
			// сдвинуть левую границу на кернинг
			left += font->GetKerning(lastSymbol, symbol) * scaleX;
		//получить символ
		const FontChar& fontChar = font->GetChar(symbol);
		//получить ширину символа
		float charWidth = fontChar.width * scaleX;

		// вывести символ
		DrawSymbol(
			vec4(
				left + fontChar.screenFirstUV.x * scaleX, y + fontChar.screenFirstUV.y * scaleY,
				left + fontChar.screenSecondUV.x * scaleX, y + fontChar.screenSecondUV.y * scaleY
			),
			vec4(fontChar.firstUV.x, fontChar.firstUV.y, fontChar.secondUV.x, fontChar.secondUV.y),
			color
		);

		//сдвинуть левую границу
		left += charWidth;

		// запомнить символ
		lastSymbol = symbol;
	}
}

void TextDrawer::Flush()
{
	// если очередь пуста, делать нечего
	if(!queuedCharsCount)
		return;

	Context::LetAttributeBinding lab(context, helper->ab);
	Context::LetVertexBuffer lvb(context, 0, helper->vb);
	Context::LetIndexBuffer lib(context, 0);
	Context::LetVertexShader lvs(context, helper->vs);
	Context::LetPixelShader lps(context, helper->ps);
	Context::LetBlendState lbs(context, helper->bs);
	Context::LetCullMode lcm(context, Context::cullModeNone);
	Context::LetFillMode lfm(context, Context::fillModeSolid);
	Context::LetDepthTestFunc ldtf(context, Context::depthTestFuncAlways);
	Context::LetDepthWrite ldw(context, false);
	Context::LetUniformBuffer lub(context, helper->ugSymbols);
	Context::LetSampler ls(context, helper->uFontSampler, currentFontTexture, helper->ss);

	// загрузить символы
	helper->ugSymbols->Upload(context);

	// нарисовать
	helper->instancer->Draw(context, queuedCharsCount);

	// сбросить количество символов
	queuedCharsCount = 0;
}

ptr<TextDrawer> TextDrawer::Create(ptr<Device> device, ptr<ShaderCache> shaderCache)
{
	return NEW(TextDrawer(NEW(TextDrawerHelper(device, shaderCache))));
}

END_INANITY_GRAPHICS
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <grpc++/grpc++.h>

#include <getopt.h>

#include <chrono>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <thread>
#include <iostream>
#include <fstream>
#include <sstream>

#ifdef __linux__
#define ENABLE_ALSA
#endif

#ifdef ENABLE_ALSA
#include "audio_input_alsa.h"
#include "audio_output_alsa.h"
#endif

#include "embedded_assistant.pb.h"
#include "embedded_assistant.grpc.pb.h"

#include "assistant_config.h"
#include "audio_input.h"
#include "audio_input_file.h"
#include "json_util.h"
#include "service_account_util.h"

using google::assistant::embedded::v1alpha1::EmbeddedAssistant;
using google::assistant::embedded::v1alpha1::ConverseRequest;
using google::assistant::embedded::v1alpha1::ConverseResponse;
using google::assistant::embedded::v1alpha1::AudioInConfig;
using google::assistant::embedded::v1alpha1::AudioOutConfig;
using google::assistant::embedded::v1alpha1::DeviceConfig;
using google::assistant::embedded::v1alpha1::ConverseResponse_EventType_END_OF_UTTERANCE;

using grpc::CallCredentials;
using grpc::Channel;
using grpc::ClientReaderWriter;

static const std::string kCredentialsTypeUserAccount = "USER_ACCOUNT";
static const std::string kCredentialsTypeServiceAccount = "SERVICE_ACCOUNT";
static const std::string kALSAAudioInput = "ALSA_INPUT";

// Creates a channel to be connected to Google.
std::shared_ptr<Channel> CreateChannel(const std::string& host) {
  std::ifstream file("robots.pem");
  std::stringstream buffer;
  buffer << file.rdbuf();
  std::string roots_pem = buffer.str();

  std::cout << "assistant_sdk robots_pem: " << roots_pem << std::endl;
  ::grpc::SslCredentialsOptions ssl_opts = {roots_pem, "", ""};
  auto creds = ::grpc::SslCredentials(ssl_opts);
  std::string server = host + ":443";
  std::cout << "assistant_sdk CreateCustomChannel(" << server << ", creds, arg)"

      << std::endl << std::endl;
  ::grpc::ChannelArguments channel_args;
  return CreateCustomChannel(server, creds, channel_args);
}

void PrintUsage() {
  std::cerr << "Usage: ./run_assistant "
            << "--audio_input <" << kALSAAudioInput << "|<audio_file>] "
            << "--credentials_file <credentials_file> "
            << "--credentials_type <" << kCredentialsTypeUserAccount << "|"
            << kCredentialsTypeServiceAccount << "> "
            << "[--api_endpoint <API endpoint>]" << std::endl;
}

bool GetCommandLineFlags(
    int argc, char** argv, std::string* audio_input,
    std::string* credentials_file_path, std::string* credentials_type,
    std::string* api_endpoint) {
  const struct option long_options[] = {
    {"audio_input",      required_argument, nullptr, 'i'},
    {"credentials_file", required_argument, nullptr, 'f'},
    {"credentials_type", required_argument, nullptr, 't'},
    {"api_endpoint",     required_argument, nullptr, 'e'},
    {nullptr, 0, nullptr, 0}
  };
  *api_endpoint = ASSISTANT_ENDPOINT;
  while (true) {
    int option_index;
    int option_char =
        getopt_long(argc, argv, "i:f:t:e", long_options, &option_index);
    if (option_char == -1) {
      break;
    }
    switch (option_char) {
      case 'i':
        *audio_input = optarg;
        break;
      case 'f':
        *credentials_file_path = optarg;
        break;
      case 't':
        *credentials_type = optarg;
        if (*credentials_type != kCredentialsTypeUserAccount
            && *credentials_type != kCredentialsTypeServiceAccount) {
          std::cerr << "Invalid credentials_type: \"" << *credentials_type
                    << "\". Should be \"" << kCredentialsTypeUserAccount
                    << "\" or \"" << kCredentialsTypeServiceAccount << "\""
                    << std::endl;
          return false;
        }
        break;
      case 'e':
        *api_endpoint = optarg;
        break;
      default:
        PrintUsage();
        return false;
    }
  }
  return true;
}

int main(int argc, char** argv) {
  std::string audio_input_source, credentials_file_path, credentials_type,
              api_endpoint;
  if (!GetCommandLineFlags(argc, argv, &audio_input_source,
                           &credentials_file_path, &credentials_type,
                           &api_endpoint)) {
    return -1;
  }

  std::unique_ptr<AudioInput> audio_input;
  if (audio_input_source == kALSAAudioInput) {
#ifdef ENABLE_ALSA
    audio_input.reset(new AudioInputALSA());
#else
    std::cerr << "ALSA audio input is not supported on this platform."
              << std::endl;
    return -1;
#endif
  } else {
    std::ifstream audio_file(audio_input_source);
    if (!audio_file) {
      std::cerr << "Audio input file \"" << audio_input_source
                << "\" does not exist." << std::endl;
      return -1;
    }
    audio_input.reset(new AudioInputFile(audio_input_source));
  }

  // Read credentials file.
  std::ifstream credentials_file(credentials_file_path);
  if (!credentials_file) {
    std::cerr << "Credentials file \"" << credentials_file_path
              << "\" does not exist." << std::endl;
    return -1;
  }
  std::stringstream credentials_buffer;
  credentials_buffer << credentials_file.rdbuf();
  std::string credentials = credentials_buffer.str();
  std::shared_ptr<CallCredentials> call_credentials;
  if (credentials_type == kCredentialsTypeServiceAccount) {
    call_credentials = GetServiceAccountCredentialsOrNull(credentials);
  } else {
    call_credentials = grpc::GoogleRefreshTokenCredentials(credentials);
  }
  if (call_credentials.get() == nullptr) {
    std::cerr << "Credentials file \"" << credentials_file_path
              << "\" is invalid. Check step 5 in README for how to get valid "
              << "credentials." << std::endl;
    return -1;
  }

  auto channel = CreateChannel(api_endpoint);
  std::unique_ptr<EmbeddedAssistant::Stub> assistant(
      EmbeddedAssistant::NewStub(channel));

  ConverseRequest request;
  auto* converse_config = request.mutable_config();
  converse_config->mutable_audio_in_config()->set_encoding(
      AudioInConfig::LINEAR16);
  converse_config->mutable_audio_in_config()->set_sample_rate_hertz(16000);
  converse_config->mutable_audio_out_config()->set_encoding(
      AudioOutConfig::LINEAR16);
  converse_config->mutable_audio_out_config()->set_sample_rate_hertz(16000);
  if (credentials_type == kCredentialsTypeServiceAccount) {
    converse_config->mutable_converse_state()->set_is_signed_out_mode(true);
  }

  auto* converse_context =
      converse_config->mutable_converse_state()->mutable_context();
  converse_context->set_third_party_context("{'current_channel': 'News'}");

  // Begin a stream.
  grpc::ClientContext context;
  context.set_fail_fast(false);
  context.set_credentials(call_credentials);

  std::shared_ptr<ClientReaderWriter<ConverseRequest, ConverseResponse>>
      stream(std::move(assistant->Converse(&context)));
  // Write config in first stream.
  std::cout << "assistant_sdk wrote first request: "
            << request.ShortDebugString() << std::endl;
  stream->Write(request);

#ifdef ENABLE_ALSA
  AudioOutputALSA audio_output;
  audio_output.Start();
#endif

  audio_input->AddDataListener(
    [stream, &request](std::shared_ptr<std::vector<unsigned char>> data) {
      request.set_audio_in(&((*data)[0]), data->size());
      stream->Write(request);
  });
  audio_input->AddStopListener([stream]() {
    stream->WritesDone();
  });
  audio_input->Start();

  // Read responses.
  std::cout << "assistant_sdk waiting for response ... " << std::endl;
  ConverseResponse response;
  while (stream->Read(&response)) {  // Returns false when no more to read.
    std::cout << "assistant_sdk Got a response \n";

    if ((response.has_error() || response.has_audio_out() ||
        response.event_type() == ConverseResponse_EventType_END_OF_UTTERANCE)
        && audio_input->IsRunning()) {
      // Synchronously stops audio input.
      audio_input->Stop();
    }

    if (response.has_audio_out()) {
      // CUSTOMIZE: play back audio_out here.
      std::cout << "assistant_sdk play back audio data here." << std::endl;
#ifdef ENABLE_ALSA
      std::shared_ptr<std::vector<unsigned char>>
          data(new std::vector<unsigned char>);
      data->resize(response.audio_out().audio_data().length());
      memcpy(&((*data)[0]), response.audio_out().audio_data().c_str(),
          response.audio_out().audio_data().length());
      audio_output.Send(data);
#endif
    }
    if (response.has_interim_spoken_request_text()) {
      // CUSTOMIZE: render interim spoken request on screen
      std::cout << "assistant_sdk response: \n"
                << response.ShortDebugString() << std::endl;
    }
  }

#ifdef ENABLE_ALSA
  audio_output.Stop();
#endif

  grpc::Status status = stream->Finish();
  if (!status.ok()) {
    // Report the RPC failure.
    std::cerr << "assistant_sdk failed, error: " <<
              status.error_message() << std::endl;
    return -1;
  }
  return 0;
}
<commit_msg>Fix #1<commit_after>/*
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <grpc++/grpc++.h>

#include <getopt.h>

#include <chrono>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <thread>
#include <iostream>
#include <fstream>
#include <sstream>

#ifdef __linux__
#define ENABLE_ALSA
#endif

#ifdef ENABLE_ALSA
#include "audio_input_alsa.h"
#include "audio_output_alsa.h"
#endif

#include "embedded_assistant.pb.h"
#include "embedded_assistant.grpc.pb.h"

#include "assistant_config.h"
#include "audio_input.h"
#include "audio_input_file.h"
#include "json_util.h"
#include "service_account_util.h"

using google::assistant::embedded::v1alpha1::EmbeddedAssistant;
using google::assistant::embedded::v1alpha1::ConverseRequest;
using google::assistant::embedded::v1alpha1::ConverseResponse;
using google::assistant::embedded::v1alpha1::AudioInConfig;
using google::assistant::embedded::v1alpha1::AudioOutConfig;
using google::assistant::embedded::v1alpha1::ConverseResponse_EventType_END_OF_UTTERANCE;

using grpc::CallCredentials;
using grpc::Channel;
using grpc::ClientReaderWriter;

static const std::string kCredentialsTypeUserAccount = "USER_ACCOUNT";
static const std::string kCredentialsTypeServiceAccount = "SERVICE_ACCOUNT";
static const std::string kALSAAudioInput = "ALSA_INPUT";

// Creates a channel to be connected to Google.
std::shared_ptr<Channel> CreateChannel(const std::string& host) {
  std::ifstream file("robots.pem");
  std::stringstream buffer;
  buffer << file.rdbuf();
  std::string roots_pem = buffer.str();

  std::cout << "assistant_sdk robots_pem: " << roots_pem << std::endl;
  ::grpc::SslCredentialsOptions ssl_opts = {roots_pem, "", ""};
  auto creds = ::grpc::SslCredentials(ssl_opts);
  std::string server = host + ":443";
  std::cout << "assistant_sdk CreateCustomChannel(" << server << ", creds, arg)"

      << std::endl << std::endl;
  ::grpc::ChannelArguments channel_args;
  return CreateCustomChannel(server, creds, channel_args);
}

void PrintUsage() {
  std::cerr << "Usage: ./run_assistant "
            << "--audio_input <" << kALSAAudioInput << "|<audio_file>] "
            << "--credentials_file <credentials_file> "
            << "--credentials_type <" << kCredentialsTypeUserAccount << "|"
            << kCredentialsTypeServiceAccount << "> "
            << "[--api_endpoint <API endpoint>]" << std::endl;
}

bool GetCommandLineFlags(
    int argc, char** argv, std::string* audio_input,
    std::string* credentials_file_path, std::string* credentials_type,
    std::string* api_endpoint) {
  const struct option long_options[] = {
    {"audio_input",      required_argument, nullptr, 'i'},
    {"credentials_file", required_argument, nullptr, 'f'},
    {"credentials_type", required_argument, nullptr, 't'},
    {"api_endpoint",     required_argument, nullptr, 'e'},
    {nullptr, 0, nullptr, 0}
  };
  *api_endpoint = ASSISTANT_ENDPOINT;
  while (true) {
    int option_index;
    int option_char =
        getopt_long(argc, argv, "i:f:t:e", long_options, &option_index);
    if (option_char == -1) {
      break;
    }
    switch (option_char) {
      case 'i':
        *audio_input = optarg;
        break;
      case 'f':
        *credentials_file_path = optarg;
        break;
      case 't':
        *credentials_type = optarg;
        if (*credentials_type != kCredentialsTypeUserAccount
            && *credentials_type != kCredentialsTypeServiceAccount) {
          std::cerr << "Invalid credentials_type: \"" << *credentials_type
                    << "\". Should be \"" << kCredentialsTypeUserAccount
                    << "\" or \"" << kCredentialsTypeServiceAccount << "\""
                    << std::endl;
          return false;
        }
        break;
      case 'e':
        *api_endpoint = optarg;
        break;
      default:
        PrintUsage();
        return false;
    }
  }
  return true;
}

int main(int argc, char** argv) {
  std::string audio_input_source, credentials_file_path, credentials_type,
              api_endpoint;
  if (!GetCommandLineFlags(argc, argv, &audio_input_source,
                           &credentials_file_path, &credentials_type,
                           &api_endpoint)) {
    return -1;
  }

  std::unique_ptr<AudioInput> audio_input;
  if (audio_input_source == kALSAAudioInput) {
#ifdef ENABLE_ALSA
    audio_input.reset(new AudioInputALSA());
#else
    std::cerr << "ALSA audio input is not supported on this platform."
              << std::endl;
    return -1;
#endif
  } else {
    std::ifstream audio_file(audio_input_source);
    if (!audio_file) {
      std::cerr << "Audio input file \"" << audio_input_source
                << "\" does not exist." << std::endl;
      return -1;
    }
    audio_input.reset(new AudioInputFile(audio_input_source));
  }

  // Read credentials file.
  std::ifstream credentials_file(credentials_file_path);
  if (!credentials_file) {
    std::cerr << "Credentials file \"" << credentials_file_path
              << "\" does not exist." << std::endl;
    return -1;
  }
  std::stringstream credentials_buffer;
  credentials_buffer << credentials_file.rdbuf();
  std::string credentials = credentials_buffer.str();
  std::shared_ptr<CallCredentials> call_credentials;
  if (credentials_type == kCredentialsTypeServiceAccount) {
    call_credentials = GetServiceAccountCredentialsOrNull(credentials);
  } else {
    call_credentials = grpc::GoogleRefreshTokenCredentials(credentials);
  }
  if (call_credentials.get() == nullptr) {
    std::cerr << "Credentials file \"" << credentials_file_path
              << "\" is invalid. Check step 5 in README for how to get valid "
              << "credentials." << std::endl;
    return -1;
  }

  auto channel = CreateChannel(api_endpoint);
  std::unique_ptr<EmbeddedAssistant::Stub> assistant(
      EmbeddedAssistant::NewStub(channel));

  ConverseRequest request;
  auto* converse_config = request.mutable_config();
  converse_config->mutable_audio_in_config()->set_encoding(
      AudioInConfig::LINEAR16);
  converse_config->mutable_audio_in_config()->set_sample_rate_hertz(16000);
  converse_config->mutable_audio_out_config()->set_encoding(
      AudioOutConfig::LINEAR16);
  converse_config->mutable_audio_out_config()->set_sample_rate_hertz(16000);
  if (credentials_type == kCredentialsTypeServiceAccount) {
    converse_config->mutable_converse_state()->set_is_signed_out_mode(true);
  }

  auto* converse_context =
      converse_config->mutable_converse_state()->mutable_context();
  converse_context->set_third_party_context("{'current_channel': 'News'}");

  // Begin a stream.
  grpc::ClientContext context;
  context.set_fail_fast(false);
  context.set_credentials(call_credentials);

  std::shared_ptr<ClientReaderWriter<ConverseRequest, ConverseResponse>>
      stream(std::move(assistant->Converse(&context)));
  // Write config in first stream.
  std::cout << "assistant_sdk wrote first request: "
            << request.ShortDebugString() << std::endl;
  stream->Write(request);

#ifdef ENABLE_ALSA
  AudioOutputALSA audio_output;
  audio_output.Start();
#endif

  audio_input->AddDataListener(
    [stream, &request](std::shared_ptr<std::vector<unsigned char>> data) {
      request.set_audio_in(&((*data)[0]), data->size());
      stream->Write(request);
  });
  audio_input->AddStopListener([stream]() {
    stream->WritesDone();
  });
  audio_input->Start();

  // Read responses.
  std::cout << "assistant_sdk waiting for response ... " << std::endl;
  ConverseResponse response;
  while (stream->Read(&response)) {  // Returns false when no more to read.
    std::cout << "assistant_sdk Got a response \n";

    if ((response.has_error() || response.has_audio_out() ||
        response.event_type() == ConverseResponse_EventType_END_OF_UTTERANCE)
        && audio_input->IsRunning()) {
      // Synchronously stops audio input.
      audio_input->Stop();
    }

    if (response.has_audio_out()) {
      // CUSTOMIZE: play back audio_out here.
      std::cout << "assistant_sdk play back audio data here." << std::endl;
#ifdef ENABLE_ALSA
      std::shared_ptr<std::vector<unsigned char>>
          data(new std::vector<unsigned char>);
      data->resize(response.audio_out().audio_data().length());
      memcpy(&((*data)[0]), response.audio_out().audio_data().c_str(),
          response.audio_out().audio_data().length());
      audio_output.Send(data);
#endif
    }
    if (response.has_interim_spoken_request_text()) {
      // CUSTOMIZE: render interim spoken request on screen
      std::cout << "assistant_sdk response: \n"
                << response.ShortDebugString() << std::endl;
    }
  }

#ifdef ENABLE_ALSA
  audio_output.Stop();
#endif

  grpc::Status status = stream->Finish();
  if (!status.ok()) {
    // Report the RPC failure.
    std::cerr << "assistant_sdk failed, error: " <<
              status.error_message() << std::endl;
    return -1;
  }
  return 0;
}
<|endoftext|>


<commit_before>// local
#include "Object.hpp"

#include "core/utils/exceptions.h"

using namespace corryvreckan;

Object::Object() : m_detectorID(), m_timestamp(0) {}
Object::Object(std::string detectorID) : m_detectorID(detectorID), m_timestamp(0) {}
Object::Object(double timestamp) : m_detectorID(), m_timestamp(timestamp) {}
Object::Object(std::string detectorID, double timestamp) : m_detectorID(detectorID), m_timestamp(timestamp) {}
Object::~Object() {}

ClassImp(Object)
<commit_msg>Remove ClassImp as done for other classes in !139<commit_after>// local
#include "Object.hpp"

#include "core/utils/exceptions.h"

using namespace corryvreckan;

Object::Object() : m_detectorID(), m_timestamp(0) {}
Object::Object(std::string detectorID) : m_detectorID(detectorID), m_timestamp(0) {}
Object::Object(double timestamp) : m_detectorID(), m_timestamp(timestamp) {}
Object::Object(std::string detectorID, double timestamp) : m_detectorID(detectorID), m_timestamp(timestamp) {}
Object::~Object() {}
<|endoftext|>