<commit_before>/**
*  Copyright (C) 2018 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "geometry_collector.h"

#include <assimp/scene.h>
#include <assimp/postprocess.h>

using namespace repo::manipulator::modelconvertor::odaHelper;

GeometryCollector::GeometryCollector()
{

}

GeometryCollector::~GeometryCollector()
{
}

repo::core::model::CameraNode generateCameraNode(camera_t camera, repo::lib::RepoUUID parentID)
{
	auto node = repo::core::model::RepoBSONFactory::makeCameraNode(camera.aspectRatio, camera.farClipPlane, camera.nearClipPlane, camera.FOV, camera.eye, camera.pos, camera.up, camera.name);
	node = node.cloneAndAddParent(parentID);
	return node;
}

void GeometryCollector::addCameraNode(camera_t node)
{
	cameras.push_back(node);
}

repo::core::model::RepoNodeSet GeometryCollector::getCameraNodes(repo::lib::RepoUUID parentID)
{
	repo::core::model::RepoNodeSet camerasNodeSet;
	for (auto& camera : cameras)
		camerasNodeSet.insert(new repo::core::model::CameraNode(generateCameraNode(camera, parentID)));
	return camerasNodeSet;
}

bool GeometryCollector::hasCemaraNodes()
{
	return cameras.size();
}

repo::core::model::TransformationNode GeometryCollector::createRootNode()
{
	return repo::core::model::RepoBSONFactory::makeTransformationNode(rootMatrix, "rootNode");
}

void GeometryCollector::setCurrentMaterial(const repo_material_t &material, bool missingTexture) {

	auto checkSum = material.checksum();
	if(idxToMat.find(checkSum) == idxToMat.end()) {
		idxToMat[checkSum] = {
			repo::core::model::RepoBSONFactory::makeMaterialNode(material),
			createTextureNode(material.texturePath)
		};

		if (missingTexture)
			this->missingTextures = true;
	}
	currMat = checkSum;
}

void repo::manipulator::modelconvertor::odaHelper::GeometryCollector::setCurrentMeta(const std::pair<std::vector<std::string>, std::vector<std::string>>& meta)
{
	currentMeta = meta;
}

repo::core::model::RepoNodeSet repo::manipulator::modelconvertor::odaHelper::GeometryCollector::getMetaNodes()
{
	return metaSet;
}

mesh_data_t GeometryCollector::createMeshEntry() {
	mesh_data_t entry;
	entry.matIdx = currMat;
	entry.name = nextMeshName;
	entry.groupName = nextGroupName;
	entry.layerName = nextLayer.empty() ? "UnknownLayer" : nextLayer;
	entry.metaValues = currentMeta;

	return entry;

}

void  GeometryCollector::startMeshEntry() {

	nextMeshName = nextMeshName.empty() ? std::to_string(std::time(0)) : nextMeshName;
	nextGroupName = nextGroupName.empty() ? nextMeshName : nextGroupName;
	nextLayer = nextLayer.empty() ? nextMeshName : nextLayer;

	if (meshData.find(nextGroupName) == meshData.end()) {
		meshData[nextGroupName] = std::unordered_map<std::string, std::unordered_map<int, mesh_data_t>>();
	}

	if (meshData[nextGroupName].find(nextLayer) == meshData[nextGroupName].end()) {
		meshData[nextGroupName][nextLayer] = std::unordered_map<int, mesh_data_t>();
	}

	if (meshData[nextGroupName][nextLayer].find(currMat) == meshData[nextGroupName][nextLayer].end()) {
		meshData[nextGroupName][nextLayer][currMat] = createMeshEntry();
	}
	currentEntry = &meshData[nextGroupName][nextLayer][currMat];

}

void  GeometryCollector::stopMeshEntry() {
	if(currentEntry)
		currentEntry->vToVIndex.clear();
	nextMeshName = "";
}

void GeometryCollector::addFace(
	const std::vector<repo::lib::RepoVector3D64> &vertices,
	const std::vector<repo::lib::RepoVector2D>& uvCoords)
{
	if (!meshData.size()) startMeshEntry();
	repo_face_t face;
	for (auto i = 0; i < vertices.size(); ++i) {
		auto& v = vertices[i];
		if (currentEntry->vToVIndex.find(v) == currentEntry->vToVIndex.end()) {
			currentEntry->vToVIndex[v] = currentEntry->rawVertices.size();
			currentEntry->rawVertices.push_back(v);
			if (i < uvCoords.size())
				currentEntry->uvCoords.push_back(uvCoords[i]);

			if (currentEntry->boundingBox.size()) {
				currentEntry->boundingBox[0][0] = currentEntry->boundingBox[0][0] > v.x ? (float) v.x : currentEntry->boundingBox[0][0];
				currentEntry->boundingBox[0][1] = currentEntry->boundingBox[0][1] > v.y ? (float) v.y : currentEntry->boundingBox[0][1];
				currentEntry->boundingBox[0][2] = currentEntry->boundingBox[0][2] > v.z ? (float) v.z : currentEntry->boundingBox[0][2];

				currentEntry->boundingBox[1][0] = currentEntry->boundingBox[1][0] < v.x ? (float) v.x : currentEntry->boundingBox[1][0];
				currentEntry->boundingBox[1][1] = currentEntry->boundingBox[1][1] < v.y ? (float) v.y : currentEntry->boundingBox[1][1];
				currentEntry->boundingBox[1][2] = currentEntry->boundingBox[1][2] < v.z ? (float) v.z : currentEntry->boundingBox[1][2];
			}
			else {
				currentEntry->boundingBox.push_back({ (float)v.x, (float)v.y, (float)v.z });
				currentEntry->boundingBox.push_back({ (float)v.x, (float)v.y, (float)v.z });
			}

			if (minMeshBox.size()) {
				minMeshBox[0] = v.x < minMeshBox[0] ? v.x : minMeshBox[0];
				minMeshBox[1] = v.y < minMeshBox[1] ? v.y : minMeshBox[1];
				minMeshBox[2] = v.z < minMeshBox[2] ? v.z : minMeshBox[2];
			}
			else {
				minMeshBox = { v.x, v.y, v.z };
			}
		}
		face.push_back(currentEntry->vToVIndex[v]);
	}
	currentEntry->faces.push_back(face);
}

repo::core::model::RepoNodeSet GeometryCollector::getMeshNodes(const repo::core::model::TransformationNode& root) {
	repo::core::model::RepoNodeSet res;
	auto dummyCol = std::vector<repo_color4d_t>();
	auto dummyOutline = std::vector<std::vector<float>>();

	std::unordered_map<std::string, repo::core::model::TransformationNode*> layerToTrans;

	auto rootId = root.getSharedID();
	repoDebug << "Mesh data: " << meshData.size();
	for (const auto &meshGroupEntry : meshData) {
		for (const auto &meshLayerEntry : meshGroupEntry.second) {
			for (const auto &meshMatEntry : meshLayerEntry.second) {
				if (!meshMatEntry.second.rawVertices.size()) continue;

				auto uvChannels = meshMatEntry.second.uvCoords.size() ?
					std::vector<std::vector<repo::lib::RepoVector2D>>{meshMatEntry.second.uvCoords} :
					std::vector<std::vector<repo::lib::RepoVector2D>>();

				if (layerToTrans.find(meshLayerEntry.first) == layerToTrans.end()) {
					layerToTrans[meshLayerEntry.first] = createTransNode(meshLayerEntry.first, rootId);
					transNodes.insert(layerToTrans[meshLayerEntry.first]);
				}

				std::vector<repo::lib::RepoVector3D> vertices32;
				vertices32.reserve(meshMatEntry.second.rawVertices.size());

				for (const auto &v : meshMatEntry.second.rawVertices) {
					vertices32.push_back({ (float)(v.x - minMeshBox[0]), (float)(v.y - minMeshBox[1]), (float)(v.z - minMeshBox[2]) });
				}

				auto meshNode = repo::core::model::RepoBSONFactory::makeMeshNode(
					vertices32,
					meshMatEntry.second.faces,
					std::vector<repo::lib::RepoVector3D>(),
					meshMatEntry.second.boundingBox,
					uvChannels,
					dummyCol,
					dummyOutline,
					meshGroupEntry.first,
					{ layerToTrans[meshLayerEntry.first]->getSharedID() }
				);

				auto& metaValues = meshMatEntry.second.metaValues;

				if (!metaValues.first.empty())
				{
					metaSet.insert(new repo::core::model::MetadataNode(repo::core::model::RepoBSONFactory::makeMetaDataNode(metaValues.first, metaValues.second, meshMatEntry.second.name,
					{
						meshNode.getSharedID()
					})));
				}

				if (matToMeshes.find(meshMatEntry.second.matIdx) == matToMeshes.end()) {
					matToMeshes[meshMatEntry.second.matIdx] = std::vector<repo::lib::RepoUUID>();
				}
				matToMeshes[meshMatEntry.second.matIdx].push_back(meshNode.getSharedID());

				res.insert(new repo::core::model::MeshNode(meshNode));
			}
		}
	}

	transNodes.insert(new repo::core::model::TransformationNode(root));
	return res;
}

repo::core::model::TransformationNode*  GeometryCollector::createTransNode(
	const std::string &name,
	const repo::lib::RepoUUID &parentId) {
	return new repo::core::model::TransformationNode(repo::core::model::RepoBSONFactory::makeTransformationNode(repo::lib::RepoMatrix(), name, { parentId }));
}

void repo::manipulator::modelconvertor::odaHelper::GeometryCollector::setRootMatrix(repo::lib::RepoMatrix matrix)
{
	rootMatrix = matrix;
}

bool GeometryCollector::hasMissingTextures()
{
	return missingTextures;
}

void GeometryCollector::getMaterialAndTextureNodes(repo::core::model::RepoNodeSet& materials, repo::core::model::RepoNodeSet& textures) {

	materials.clear();
	textures.clear();

	for (const auto &matPair : idxToMat) {
		auto matIdx = matPair.first;
		if (matToMeshes.find(matIdx) != matToMeshes.end()) {
			auto& materialNode = matPair.second.first;
			auto& textureNode = matPair.second.second;

			auto matNode = new repo::core::model::MaterialNode(materialNode.cloneAndAddParent(matToMeshes[matIdx]));
			materials.insert(matNode);

			if (!textureNode.isEmpty()) {
				auto texNode = new repo::core::model::TextureNode(textureNode.cloneAndAddParent(matNode->getSharedID()));
				textures.insert(texNode);
			}
		}
		else {
			repoDebug << "Did not find matTo Meshes: " << matIdx;
		}
	}
}

repo::core::model::TextureNode GeometryCollector::createTextureNode(const std::string& texturePath)
{
	std::ifstream::pos_type size;
	std::ifstream file(texturePath, std::ios::in | std::ios::binary | std::ios::ate);
	char *memblock = nullptr;
	if (!file.is_open())
		return repo::core::model::TextureNode();

	size = file.tellg();
	memblock = new char[size];
	file.seekg(0, std::ios::beg);
	file.read(memblock, size);
	file.close();

	auto texnode = repo::core::model::RepoBSONFactory::makeTextureNode(
		texturePath,
		(const char*)memblock,
		size,
		1,
		0,
		REPO_NODE_API_LEVEL_1
	);

	delete[] memblock;

	return texnode;
}<commit_msg>ISSUE #291 - test: remove positioning to origin<commit_after>/**
*  Copyright (C) 2018 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "geometry_collector.h"

#include <assimp/scene.h>
#include <assimp/postprocess.h>

using namespace repo::manipulator::modelconvertor::odaHelper;

GeometryCollector::GeometryCollector()
{

}

GeometryCollector::~GeometryCollector()
{
}

repo::core::model::CameraNode generateCameraNode(camera_t camera, repo::lib::RepoUUID parentID)
{
	auto node = repo::core::model::RepoBSONFactory::makeCameraNode(camera.aspectRatio, camera.farClipPlane, camera.nearClipPlane, camera.FOV, camera.eye, camera.pos, camera.up, camera.name);
	node = node.cloneAndAddParent(parentID);
	return node;
}

void GeometryCollector::addCameraNode(camera_t node)
{
	cameras.push_back(node);
}

repo::core::model::RepoNodeSet GeometryCollector::getCameraNodes(repo::lib::RepoUUID parentID)
{
	repo::core::model::RepoNodeSet camerasNodeSet;
	for (auto& camera : cameras)
		camerasNodeSet.insert(new repo::core::model::CameraNode(generateCameraNode(camera, parentID)));
	return camerasNodeSet;
}

bool GeometryCollector::hasCemaraNodes()
{
	return cameras.size();
}

repo::core::model::TransformationNode GeometryCollector::createRootNode()
{
	return repo::core::model::RepoBSONFactory::makeTransformationNode(rootMatrix, "rootNode");
}

void GeometryCollector::setCurrentMaterial(const repo_material_t &material, bool missingTexture) {

	auto checkSum = material.checksum();
	if(idxToMat.find(checkSum) == idxToMat.end()) {
		idxToMat[checkSum] = {
			repo::core::model::RepoBSONFactory::makeMaterialNode(material),
			createTextureNode(material.texturePath)
		};

		if (missingTexture)
			this->missingTextures = true;
	}
	currMat = checkSum;
}

void repo::manipulator::modelconvertor::odaHelper::GeometryCollector::setCurrentMeta(const std::pair<std::vector<std::string>, std::vector<std::string>>& meta)
{
	currentMeta = meta;
}

repo::core::model::RepoNodeSet repo::manipulator::modelconvertor::odaHelper::GeometryCollector::getMetaNodes()
{
	return metaSet;
}

mesh_data_t GeometryCollector::createMeshEntry() {
	mesh_data_t entry;
	entry.matIdx = currMat;
	entry.name = nextMeshName;
	entry.groupName = nextGroupName;
	entry.layerName = nextLayer.empty() ? "UnknownLayer" : nextLayer;
	entry.metaValues = currentMeta;

	return entry;

}

void  GeometryCollector::startMeshEntry() {

	nextMeshName = nextMeshName.empty() ? std::to_string(std::time(0)) : nextMeshName;
	nextGroupName = nextGroupName.empty() ? nextMeshName : nextGroupName;
	nextLayer = nextLayer.empty() ? nextMeshName : nextLayer;

	if (meshData.find(nextGroupName) == meshData.end()) {
		meshData[nextGroupName] = std::unordered_map<std::string, std::unordered_map<int, mesh_data_t>>();
	}

	if (meshData[nextGroupName].find(nextLayer) == meshData[nextGroupName].end()) {
		meshData[nextGroupName][nextLayer] = std::unordered_map<int, mesh_data_t>();
	}

	if (meshData[nextGroupName][nextLayer].find(currMat) == meshData[nextGroupName][nextLayer].end()) {
		meshData[nextGroupName][nextLayer][currMat] = createMeshEntry();
	}
	currentEntry = &meshData[nextGroupName][nextLayer][currMat];

}

void  GeometryCollector::stopMeshEntry() {
	if(currentEntry)
		currentEntry->vToVIndex.clear();
	nextMeshName = "";
}

void GeometryCollector::addFace(
	const std::vector<repo::lib::RepoVector3D64> &vertices,
	const std::vector<repo::lib::RepoVector2D>& uvCoords)
{
	if (!meshData.size()) startMeshEntry();
	repo_face_t face;
	for (auto i = 0; i < vertices.size(); ++i) {
		auto& v = vertices[i];
		if (currentEntry->vToVIndex.find(v) == currentEntry->vToVIndex.end()) {
			currentEntry->vToVIndex[v] = currentEntry->rawVertices.size();
			currentEntry->rawVertices.push_back(v);
			if (i < uvCoords.size())
				currentEntry->uvCoords.push_back(uvCoords[i]);

			if (currentEntry->boundingBox.size()) {
				currentEntry->boundingBox[0][0] = currentEntry->boundingBox[0][0] > v.x ? (float) v.x : currentEntry->boundingBox[0][0];
				currentEntry->boundingBox[0][1] = currentEntry->boundingBox[0][1] > v.y ? (float) v.y : currentEntry->boundingBox[0][1];
				currentEntry->boundingBox[0][2] = currentEntry->boundingBox[0][2] > v.z ? (float) v.z : currentEntry->boundingBox[0][2];

				currentEntry->boundingBox[1][0] = currentEntry->boundingBox[1][0] < v.x ? (float) v.x : currentEntry->boundingBox[1][0];
				currentEntry->boundingBox[1][1] = currentEntry->boundingBox[1][1] < v.y ? (float) v.y : currentEntry->boundingBox[1][1];
				currentEntry->boundingBox[1][2] = currentEntry->boundingBox[1][2] < v.z ? (float) v.z : currentEntry->boundingBox[1][2];
			}
			else {
				currentEntry->boundingBox.push_back({ (float)v.x, (float)v.y, (float)v.z });
				currentEntry->boundingBox.push_back({ (float)v.x, (float)v.y, (float)v.z });
			}

			if (minMeshBox.size()) {
				minMeshBox[0] = v.x < minMeshBox[0] ? v.x : minMeshBox[0];
				minMeshBox[1] = v.y < minMeshBox[1] ? v.y : minMeshBox[1];
				minMeshBox[2] = v.z < minMeshBox[2] ? v.z : minMeshBox[2];
			}
			else {
				minMeshBox = { v.x, v.y, v.z };
			}
		}
		face.push_back(currentEntry->vToVIndex[v]);
	}
	currentEntry->faces.push_back(face);
}

repo::core::model::RepoNodeSet GeometryCollector::getMeshNodes(const repo::core::model::TransformationNode& root) {
	repo::core::model::RepoNodeSet res;
	auto dummyCol = std::vector<repo_color4d_t>();
	auto dummyOutline = std::vector<std::vector<float>>();

	std::unordered_map<std::string, repo::core::model::TransformationNode*> layerToTrans;

	auto rootId = root.getSharedID();
	repoDebug << "Mesh data: " << meshData.size();
	for (const auto &meshGroupEntry : meshData) {
		for (const auto &meshLayerEntry : meshGroupEntry.second) {
			for (const auto &meshMatEntry : meshLayerEntry.second) {
				if (!meshMatEntry.second.rawVertices.size()) continue;

				auto uvChannels = meshMatEntry.second.uvCoords.size() ?
					std::vector<std::vector<repo::lib::RepoVector2D>>{meshMatEntry.second.uvCoords} :
					std::vector<std::vector<repo::lib::RepoVector2D>>();

				if (layerToTrans.find(meshLayerEntry.first) == layerToTrans.end()) {
					layerToTrans[meshLayerEntry.first] = createTransNode(meshLayerEntry.first, rootId);
					transNodes.insert(layerToTrans[meshLayerEntry.first]);
				}

				std::vector<repo::lib::RepoVector3D> vertices32;
				vertices32.reserve(meshMatEntry.second.rawVertices.size());

				for (const auto &v : meshMatEntry.second.rawVertices) {
					vertices32.push_back({ (float)(v.x), (float)(v.y), (float)(v.z) });
				}

				auto meshNode = repo::core::model::RepoBSONFactory::makeMeshNode(
					vertices32,
					meshMatEntry.second.faces,
					std::vector<repo::lib::RepoVector3D>(),
					meshMatEntry.second.boundingBox,
					uvChannels,
					dummyCol,
					dummyOutline,
					meshGroupEntry.first,
					{ layerToTrans[meshLayerEntry.first]->getSharedID() }
				);

				auto& metaValues = meshMatEntry.second.metaValues;

				if (!metaValues.first.empty())
				{
					metaSet.insert(new repo::core::model::MetadataNode(repo::core::model::RepoBSONFactory::makeMetaDataNode(metaValues.first, metaValues.second, meshMatEntry.second.name,
					{
						meshNode.getSharedID()
					})));
				}

				if (matToMeshes.find(meshMatEntry.second.matIdx) == matToMeshes.end()) {
					matToMeshes[meshMatEntry.second.matIdx] = std::vector<repo::lib::RepoUUID>();
				}
				matToMeshes[meshMatEntry.second.matIdx].push_back(meshNode.getSharedID());

				res.insert(new repo::core::model::MeshNode(meshNode));
			}
		}
	}

	transNodes.insert(new repo::core::model::TransformationNode(root));
	return res;
}

repo::core::model::TransformationNode*  GeometryCollector::createTransNode(
	const std::string &name,
	const repo::lib::RepoUUID &parentId) {
	return new repo::core::model::TransformationNode(repo::core::model::RepoBSONFactory::makeTransformationNode(repo::lib::RepoMatrix(), name, { parentId }));
}

void repo::manipulator::modelconvertor::odaHelper::GeometryCollector::setRootMatrix(repo::lib::RepoMatrix matrix)
{
	rootMatrix = matrix;
}

bool GeometryCollector::hasMissingTextures()
{
	return missingTextures;
}

void GeometryCollector::getMaterialAndTextureNodes(repo::core::model::RepoNodeSet& materials, repo::core::model::RepoNodeSet& textures) {

	materials.clear();
	textures.clear();

	for (const auto &matPair : idxToMat) {
		auto matIdx = matPair.first;
		if (matToMeshes.find(matIdx) != matToMeshes.end()) {
			auto& materialNode = matPair.second.first;
			auto& textureNode = matPair.second.second;

			auto matNode = new repo::core::model::MaterialNode(materialNode.cloneAndAddParent(matToMeshes[matIdx]));
			materials.insert(matNode);

			if (!textureNode.isEmpty()) {
				auto texNode = new repo::core::model::TextureNode(textureNode.cloneAndAddParent(matNode->getSharedID()));
				textures.insert(texNode);
			}
		}
		else {
			repoDebug << "Did not find matTo Meshes: " << matIdx;
		}
	}
}

repo::core::model::TextureNode GeometryCollector::createTextureNode(const std::string& texturePath)
{
	std::ifstream::pos_type size;
	std::ifstream file(texturePath, std::ios::in | std::ios::binary | std::ios::ate);
	char *memblock = nullptr;
	if (!file.is_open())
		return repo::core::model::TextureNode();

	size = file.tellg();
	memblock = new char[size];
	file.seekg(0, std::ios::beg);
	file.read(memblock, size);
	file.close();

	auto texnode = repo::core::model::RepoBSONFactory::makeTextureNode(
		texturePath,
		(const char*)memblock,
		size,
		1,
		0,
		REPO_NODE_API_LEVEL_1
	);

	delete[] memblock;

	return texnode;
}<|endoftext|>


<commit_before>/*
 *  RudeSkinnedMesh.cpp
 *
 *  Bork3D Game Engine
 *  Copyright (c) 2009 Bork 3D LLC. All rights reserved.
 *
 */

#include "RudeSkinnedMesh.h"

#include "RudeDebug.h"
#include "RudeGL.h"
#include "RudeFile.h"
#include "RudePerf.h"
#include "RudeTextureManager.h"
#include "RudeTweaker.h"

bool gDebugAnim = false;
RUDE_TWEAK(DebugAnim, kBool, gDebugAnim);

float gDebugAnimFrame = 0;
RUDE_TWEAK(DebugAnimFrame, kFloat, gDebugAnimFrame);

RudeSkinnedMesh::RudeSkinnedMesh(RudeObject *owner)
: RudeMesh(owner)
, m_frame(0.0f)
, m_fps(24.0f)
, m_toFrame(0.0f)
, m_animateTo(false)
{
}

RudeSkinnedMesh::~RudeSkinnedMesh()
{
}

int RudeSkinnedMesh::Load(const char *name)
{
	RUDE_REPORT("RudeSkinnedMesh::Load %s\n", name);

	if(RudeMesh::Load(name))
		return -1;

	for(unsigned int i = 0; i < m_model.nNumMesh; i++)
	{
		SPODMesh *mesh = &m_model.pMesh[i];

		for(int b = 0; b < mesh->sBoneBatches.nBatchCnt; b++)
		{
			int offset = mesh->sBoneBatches.pnBatchOffset[b];
			int end = mesh->sBoneBatches.pnBatchOffset[b+1];

			if(b == (mesh->sBoneBatches.nBatchCnt - 1))
				end = mesh->nNumFaces;

			int numfaces = (end - offset);

			RUDE_REPORT("  Mesh %d-%d: %d tris\n", i, b, numfaces);
		}

		RUDE_ASSERT(mesh->sBoneIdx.eType == EPODDataUnsignedByte, "Bone indices must be unsigned byte");
		RUDE_ASSERT(mesh->sBoneWeight.eType == EPODDataFloat, "Bone weight must be float");
		RUDE_ASSERT(mesh->sVertex.eType == EPODDataFloat, "Mesh verts should be float");
	}

	return 0;

}

void RudeSkinnedMesh::SetFrame(float f)
{
	m_animateTo = false;
	m_frame = f;
}

void RudeSkinnedMesh::AnimateTo(float f)
{
	m_animateTo = true;
	m_toFrame = f;
}

void RudeSkinnedMesh::NextFrame(float delta)
{

	if(m_animateTo)
	{
		if(m_toFrame > m_frame)
		{
			m_frame += delta * m_fps;

			if(m_frame > m_toFrame)
			{
				m_frame = m_toFrame;
				m_animateTo = false;
			}
		}
		else
		{
			m_frame -= delta * m_fps;

			if(m_frame < m_toFrame)
			{
				m_frame = m_toFrame;
				m_animateTo = false;
			}
		}

	}

	m_model.SetFrame(m_frame);

	if(gDebugAnim)
		m_model.SetFrame(gDebugAnimFrame);
}

void RudeSkinnedMesh::Render()
{

#ifdef RUDE_OGLES
	RUDE_PERF_START(kPerfRudeSkinMeshRender);

	//int numbonemats;
	//glGetIntegerv(GL_MAX_PALETTE_MATRICES_OES, &numbonemats);
	//printf("bonemats %d\n", numbonemats);

	glMatrixMode(GL_MODELVIEW);
	PVRTMATRIX viewmat;
	glGetFloatv(GL_MODELVIEW_MATRIX, viewmat.f);

	RGL.Enable(kBackfaceCull, true);

	glCullFace(GL_FRONT);
	glFrontFace(GL_CW);

	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	RGL.EnableClient(kVertexArray, true);
	RGL.EnableClient(kTextureCoordArray, true);

	//glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

	if(m_animate)
	{
		glEnable(GL_MATRIX_PALETTE_OES);
		glEnableClientState(GL_MATRIX_INDEX_ARRAY_OES);
		glEnableClientState(GL_WEIGHT_ARRAY_OES);
	}

	//glScalef(m_scale.x(), m_scale.y(), m_scale.z());

	for(int i = 0; i < m_model.nNumNode; i++)
	{
		SPODNode *node = &m_model.pNode[i];

		if(!node->pszName)
			continue;
		if(node->pszName[0] != 'M')
			continue;

		SPODMaterial *material = &m_model.pMaterial[node->nIdxMaterial];
		SPODMesh *mesh = &m_model.pMesh[node->nIdx];

		if(m_animate)
		{
			glMatrixIndexPointerOES(mesh->sBoneIdx.n, GL_UNSIGNED_BYTE, mesh->sBoneIdx.nStride, mesh->pInterleaved + (long) mesh->sBoneIdx.pData);
			glWeightPointerOES(mesh->sBoneWeight.n, GL_FLOAT, mesh->sBoneWeight.nStride, mesh->pInterleaved + (long) mesh->sBoneWeight.pData);
		}

		int textureid = material->nIdxTexDiffuse;
		if(textureid >= 0)
			RudeTextureManager::GetInstance()->SetTexture(m_textures[textureid]);

		unsigned short *indices	= (unsigned short*) mesh->sFaces.pData;

		glVertexPointer(3, GL_FLOAT, mesh->sVertex.nStride, mesh->pInterleaved + (long)mesh->sVertex.pData);

		glTexCoordPointer(2, GL_FLOAT, mesh->psUVW->nStride, mesh->pInterleaved + (long)mesh->psUVW->pData);

		if((mesh->sVtxColours.n > 0) && (mesh->sVtxColours.eType == EPODDataRGBA))
		{
			RGL.EnableClient(kColorArray, true);
			glColorPointer(4, GL_UNSIGNED_BYTE, mesh->sVtxColours.nStride, mesh->pInterleaved + (long)mesh->sVtxColours.pData);
		}
		else
			RGL.EnableClient(kColorArray, false);

		int totalbatchcnt = 0;

		for(int b = 0; b < mesh->sBoneBatches.nBatchCnt; b++)
		{
			int batchcnt = mesh->sBoneBatches.pnBatchBoneCnt[b];

			if(m_animate)
			{
				glMatrixMode(GL_MATRIX_PALETTE_OES);

				for(int j = 0; j < batchcnt; ++j)
				{
					glCurrentPaletteMatrixOES(j);

					// Generates the world matrix for the given bone in this batch.
					PVRTMATRIX	mBoneWorld;
					int i32NodeID = mesh->sBoneBatches.pnBatches[j + totalbatchcnt];
					m_model.GetBoneWorldMatrix(mBoneWorld, *node, m_model.pNode[i32NodeID]);

					// Multiply the bone's world matrix by the view matrix to put it in view space
					PVRTMatrixMultiply(mBoneWorld, mBoneWorld, viewmat);

					// Load the bone matrix into the current palette matrix.
					glLoadMatrixf(mBoneWorld.f);
				}
			}

			totalbatchcnt += batchcnt;

			int offset = mesh->sBoneBatches.pnBatchOffset[b] * 3;
			int end = mesh->sBoneBatches.pnBatchOffset[b+1] * 3;

			if(b == (mesh->sBoneBatches.nBatchCnt - 1))
				end = mesh->nNumFaces*3;

			int numidx = (end - offset);

			glDrawElements(GL_TRIANGLES, numidx, GL_UNSIGNED_SHORT, &indices[offset]);
		}

	}

	glDisable(GL_MATRIX_PALETTE_OES);
	glDisableClientState(GL_MATRIX_INDEX_ARRAY_OES);
	glDisableClientState(GL_WEIGHT_ARRAY_OES);

	RUDE_PERF_STOP(kPerfRudeSkinMeshRender);

#endif
}
<commit_msg>first pass on software skinned mesh renderer<commit_after>/*
 *  RudeSkinnedMesh.cpp
 *
 *  Bork3D Game Engine
 *  Copyright (c) 2009 Bork 3D LLC. All rights reserved.
 *
 */

#include "RudeSkinnedMesh.h"

#include "RudeDebug.h"
#include "RudeGL.h"
#include "RudeFile.h"
#include "RudePerf.h"
#include "RudeTextureManager.h"
#include "RudeTweaker.h"

bool gDebugAnim = false;
RUDE_TWEAK(DebugAnim, kBool, gDebugAnim);

float gDebugAnimFrame = 0;
RUDE_TWEAK(DebugAnimFrame, kFloat, gDebugAnimFrame);

RudeSkinnedMesh::RudeSkinnedMesh(RudeObject *owner)
: RudeMesh(owner)
, m_frame(0.0f)
, m_fps(24.0f)
, m_toFrame(0.0f)
, m_animateTo(false)
{
}

RudeSkinnedMesh::~RudeSkinnedMesh()
{
}

int RudeSkinnedMesh::Load(const char *name)
{
	RUDE_REPORT("RudeSkinnedMesh::Load %s\n", name);

	if(RudeMesh::Load(name))
		return -1;

	for(unsigned int i = 0; i < m_model.nNumMesh; i++)
	{
		SPODMesh *mesh = &m_model.pMesh[i];

		for(int b = 0; b < mesh->sBoneBatches.nBatchCnt; b++)
		{
			int offset = mesh->sBoneBatches.pnBatchOffset[b];
			int end = mesh->sBoneBatches.pnBatchOffset[b+1];

			if(b == (mesh->sBoneBatches.nBatchCnt - 1))
				end = mesh->nNumFaces;

			int numfaces = (end - offset);

			RUDE_REPORT("  Mesh %d-%d: %d tris\n", i, b, numfaces);
		}

		RUDE_ASSERT(mesh->sBoneIdx.eType == EPODDataUnsignedByte, "Bone indices must be unsigned byte");
		RUDE_ASSERT(mesh->sBoneWeight.eType == EPODDataFloat, "Bone weight must be float");
		RUDE_ASSERT(mesh->sVertex.eType == EPODDataFloat, "Mesh verts should be float");
	}

	//GLhandleARB g_vertexShader = glCreateShaderObjectARB( GL_VERTEX_SHADER_ARB );

	return 0;

}

void RudeSkinnedMesh::SetFrame(float f)
{
	m_animateTo = false;
	m_frame = f;
}

void RudeSkinnedMesh::AnimateTo(float f)
{
	m_animateTo = true;
	m_toFrame = f;
}

void RudeSkinnedMesh::NextFrame(float delta)
{

	if(m_animateTo)
	{
		if(m_toFrame > m_frame)
		{
			m_frame += delta * m_fps;

			if(m_frame > m_toFrame)
			{
				m_frame = m_toFrame;
				m_animateTo = false;
			}
		}
		else
		{
			m_frame -= delta * m_fps;

			if(m_frame < m_toFrame)
			{
				m_frame = m_toFrame;
				m_animateTo = false;
			}
		}

	}

	m_model.SetFrame(m_frame);

	if(gDebugAnim)
		m_model.SetFrame(gDebugAnimFrame);
}

void RudeSkinnedMesh::Render()
{

#ifdef RUDE_OGLES
	RUDE_PERF_START(kPerfRudeSkinMeshRender);

	//int numbonemats;
	//glGetIntegerv(GL_MAX_PALETTE_MATRICES_OES, &numbonemats);
	//printf("bonemats %d\n", numbonemats);

	glMatrixMode(GL_MODELVIEW);
	PVRTMATRIX viewmat;
	glGetFloatv(GL_MODELVIEW_MATRIX, viewmat.f);

	RGL.Enable(kBackfaceCull, true);

	glCullFace(GL_FRONT);
	glFrontFace(GL_CW);

	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	RGL.EnableClient(kVertexArray, true);
	RGL.EnableClient(kTextureCoordArray, true);

	//glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

	if(m_animate)
	{
		glEnable(GL_MATRIX_PALETTE_OES);
		glEnableClientState(GL_MATRIX_INDEX_ARRAY_OES);
		glEnableClientState(GL_WEIGHT_ARRAY_OES);
	}

	//glScalef(m_scale.x(), m_scale.y(), m_scale.z());

	for(int i = 0; i < m_model.nNumNode; i++)
	{
		SPODNode *node = &m_model.pNode[i];

		if(!node->pszName)
			continue;
		if(node->pszName[0] != 'M')
			continue;

		SPODMaterial *material = &m_model.pMaterial[node->nIdxMaterial];
		SPODMesh *mesh = &m_model.pMesh[node->nIdx];

		if(m_animate)
		{
			glMatrixIndexPointerOES(mesh->sBoneIdx.n, GL_UNSIGNED_BYTE, mesh->sBoneIdx.nStride, mesh->pInterleaved + (long) mesh->sBoneIdx.pData);
			glWeightPointerOES(mesh->sBoneWeight.n, GL_FLOAT, mesh->sBoneWeight.nStride, mesh->pInterleaved + (long) mesh->sBoneWeight.pData);
		}

		int textureid = material->nIdxTexDiffuse;
		if(textureid >= 0)
			RudeTextureManager::GetInstance()->SetTexture(m_textures[textureid]);

		unsigned short *indices	= (unsigned short*) mesh->sFaces.pData;

		glVertexPointer(3, GL_FLOAT, mesh->sVertex.nStride, mesh->pInterleaved + (long)mesh->sVertex.pData);

		glTexCoordPointer(2, GL_FLOAT, mesh->psUVW->nStride, mesh->pInterleaved + (long)mesh->psUVW->pData);

		if((mesh->sVtxColours.n > 0) && (mesh->sVtxColours.eType == EPODDataRGBA))
		{
			RGL.EnableClient(kColorArray, true);
			glColorPointer(4, GL_UNSIGNED_BYTE, mesh->sVtxColours.nStride, mesh->pInterleaved + (long)mesh->sVtxColours.pData);
		}
		else
			RGL.EnableClient(kColorArray, false);

		int totalbatchcnt = 0;

		for(int b = 0; b < mesh->sBoneBatches.nBatchCnt; b++)
		{
			int batchcnt = mesh->sBoneBatches.pnBatchBoneCnt[b];

			if(m_animate)
			{
				glMatrixMode(GL_MATRIX_PALETTE_OES);

				for(int j = 0; j < batchcnt; ++j)
				{
					glCurrentPaletteMatrixOES(j);

					// Generates the world matrix for the given bone in this batch.
					PVRTMATRIX	mBoneWorld;
					int i32NodeID = mesh->sBoneBatches.pnBatches[j + totalbatchcnt];
					m_model.GetBoneWorldMatrix(mBoneWorld, *node, m_model.pNode[i32NodeID]);

					// Multiply the bone's world matrix by the view matrix to put it in view space
					PVRTMatrixMultiply(mBoneWorld, mBoneWorld, viewmat);

					// Load the bone matrix into the current palette matrix.
					glLoadMatrixf(mBoneWorld.f);
				}
			}

			totalbatchcnt += batchcnt;

			int offset = mesh->sBoneBatches.pnBatchOffset[b] * 3;
			int end = mesh->sBoneBatches.pnBatchOffset[b+1] * 3;

			if(b == (mesh->sBoneBatches.nBatchCnt - 1))
				end = mesh->nNumFaces*3;

			int numidx = (end - offset);

			glDrawElements(GL_TRIANGLES, numidx, GL_UNSIGNED_SHORT, &indices[offset]);
		}

	}

	glDisable(GL_MATRIX_PALETTE_OES);
	glDisableClientState(GL_MATRIX_INDEX_ARRAY_OES);
	glDisableClientState(GL_WEIGHT_ARRAY_OES);

	RUDE_PERF_STOP(kPerfRudeSkinMeshRender);

#else

	glMatrixMode(GL_MODELVIEW);
	PVRTMATRIX viewmat;
	glGetFloatv(GL_MODELVIEW_MATRIX, viewmat.f);

	RGL.Enable(kBackfaceCull, true);

	glCullFace(GL_FRONT);
	glFrontFace(GL_CW);

	RGL.EnableClient(kVertexArray, true);
	RGL.EnableClient(kTextureCoordArray, true);

	for(unsigned int i = 0; i < m_model.nNumNode; i++)
	{
		SPODNode *node = &m_model.pNode[i];

		if(!node->pszName)
			continue;
		if(node->pszName[0] != 'M')
			continue;

		SPODMaterial *material = &m_model.pMaterial[node->nIdxMaterial];
		SPODMesh *mesh = &m_model.pMesh[node->nIdx];

		int textureid = material->nIdxTexDiffuse;
		if(textureid >= 0)
			RudeTextureManager::GetInstance()->SetTexture(m_textures[textureid]);

		unsigned short *indices	= (unsigned short*) mesh->sFaces.pData;

		glVertexPointer(3, GL_FLOAT, mesh->sVertex.nStride, mesh->pInterleaved + (long)mesh->sVertex.pData);

		glTexCoordPointer(2, GL_FLOAT, mesh->psUVW->nStride, mesh->pInterleaved + (long)mesh->psUVW->pData);

		if((mesh->sVtxColours.n > 0) && (mesh->sVtxColours.eType == EPODDataRGBA))
		{
			RGL.EnableClient(kColorArray, true);
			glColorPointer(4, GL_UNSIGNED_BYTE, mesh->sVtxColours.nStride, mesh->pInterleaved + (long)mesh->sVtxColours.pData);
		}
		else
		{
			RGL.EnableClient(kColorArray, false);
			glColor4f(1.0, 1.0, 1.0, 1.0);
		}

		int totalbatchcnt = 0;

		for(int b = 0; b < mesh->sBoneBatches.nBatchCnt; b++)
		{
			int batchcnt = mesh->sBoneBatches.pnBatchBoneCnt[b];

			btTransform boneworldbt[9];

			if(m_animate)
			{
				for(int j = 0; j < batchcnt; ++j)
				{
					// Generates the world matrix for the given bone in this batch.

					PVRTMATRIX	boneworld;

					int i32NodeID = mesh->sBoneBatches.pnBatches[j + totalbatchcnt];
					m_model.GetBoneWorldMatrix(boneworld, *node, m_model.pNode[i32NodeID]);

					boneworldbt[j].setFromOpenGLMatrix(boneworld.f);
				}
			}

			totalbatchcnt += batchcnt;

			int offset = mesh->sBoneBatches.pnBatchOffset[b] * 3;
			int end = mesh->sBoneBatches.pnBatchOffset[b+1] * 3;

			if(b == (mesh->sBoneBatches.nBatchCnt - 1))
				end = mesh->nNumFaces*3;

			int numidx = (end - offset);

			for(int v = offset; v < end; v += 3)
			{
				unsigned short *idx = &indices[v];

				float verts[3][3] = { 0.0 };
				float uvs[3][2] = { 0.0 };
				float weights[3][9] = { 0.0 };
				unsigned char bones[3][9] = { 0 };

				for(int a = 0; a < 3; a++)
				{
					float *meshverts = (float*) (mesh->pInterleaved + (long)mesh->sVertex.pData + mesh->sVertex.nStride * indices[v+a]);
					float *meshuvs = (float*) (mesh->pInterleaved + (long)mesh->psUVW->pData + mesh->psUVW->nStride * indices[v+a]);
					float *meshweights = (float *) (mesh->pInterleaved + (long)mesh->sBoneWeight.pData + mesh->sBoneWeight.nStride * indices[v+a]);
					unsigned char *meshbones = (unsigned char *) (mesh->pInterleaved + (long)mesh->sBoneIdx.pData + mesh->sBoneIdx.nStride * indices[v+a]);

					btVector3 temppos(0,0,0);

					uvs[a][0] = meshuvs[0];
					uvs[a][1] = meshuvs[1];

					for(unsigned int b = 0; b < mesh->sBoneIdx.n; b++)
						bones[a][b] = meshbones[b];

					for(unsigned int w = 0; w < mesh->sBoneWeight.n; w++)
					{
						float weight = meshweights[w];
						unsigned char boneidx = meshbones[w];

						if(weight < 0.00001f)
							continue;

						btVector3 p(meshverts[0], meshverts[1], meshverts[2]);
						p = boneworldbt[boneidx] * p;
						p = p * weight;
						temppos += p;
					}

					verts[a][0] = temppos[0];
					verts[a][1] = temppos[1];
					verts[a][2] = temppos[2];
				}

				glVertexPointer(3, GL_FLOAT, 0, verts);
				glTexCoordPointer(2, GL_FLOAT, 0, uvs);

				//glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
				glDrawArrays(GL_TRIANGLES, 0, 3);
			}
		}

	}

#endif
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 - 2013 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "DispatchQueue.h"
#include "at_exit.h"

DispatchQueue::DispatchQueue(void):
  m_aborted(false),
  m_dispatchCap(1024)
{
  m_waitPredicate = [this] {
    if(m_aborted)
      throw dispatch_aborted_exception();
    return !m_dispatchQueue.empty() && m_dispatchQueue.front()->IsCommited();
  };
}

DispatchQueue::~DispatchQueue(void) {
  // Teardown:
  for(auto q = m_dispatchQueue.begin(); q != m_dispatchQueue.end(); q++)
    delete *q;
}

void DispatchQueue::Abort(void) {
  boost::lock_guard<boost::mutex> lk(m_dispatchLock);
  m_aborted = true;

  // Rip apart:
  for(auto q = m_dispatchQueue.begin(); q != m_dispatchQueue.end(); q++)
    delete *q;
  m_dispatchQueue.clear();

  // Wake up anyone who is still waiting:
  m_queueUpdated.notify_all();
}

void DispatchQueue::DispatchEventUnsafe(boost::unique_lock<boost::mutex>& lk) {
  DispatchThunkBase* thunk = m_dispatchQueue.front();
  m_dispatchQueue.pop_front();
  bool wasEmpty = m_dispatchQueue.empty();
  lk.unlock();

  auto generalCleanup = MakeAtExit(
    [this, thunk, wasEmpty] {
      delete thunk;

      // If we emptied the queue, we'd like to reobtain the lock and tell everyone
      // that the queue is now empty.
      if(wasEmpty)
        m_queueUpdated.notify_all();
    }
  );

  (*thunk)();
}

void DispatchQueue::WaitForEvent(void) {
  boost::unique_lock<boost::mutex> lk(m_dispatchLock);
  if(m_aborted)
    throw dispatch_aborted_exception();

  m_queueUpdated.wait(lk, m_waitPredicate);
  DispatchEventUnsafe(lk);
}

bool DispatchQueue::WaitForEvent(boost::chrono::duration<double, boost::milli> milliseconds) {
  boost::unique_lock<boost::mutex> lk(m_dispatchLock);
  if(m_aborted)
    throw dispatch_aborted_exception();

  m_queueUpdated.wait_for(lk, milliseconds, m_waitPredicate);
  if(m_dispatchQueue.empty())
    return false;

  DispatchEventUnsafe(lk);
  return true;
}

bool DispatchQueue::WaitForEvent(boost::chrono::steady_clock::time_point wakeTime) {
  if(wakeTime == boost::chrono::steady_clock::time_point::max())
    // Maximal wait--we can optimize by using the zero-arguments version
    return WaitForEvent(), true;

  boost::unique_lock<boost::mutex> lk(m_dispatchLock);
  if(m_aborted)
    throw dispatch_aborted_exception();

  m_queueUpdated.wait_until(lk, wakeTime, m_waitPredicate);
  if(m_dispatchQueue.empty())
    return false;

  DispatchEventUnsafe(lk);
  return true;
}

bool DispatchQueue::DispatchEvent(void) {
  boost::unique_lock<boost::mutex> lk(m_dispatchLock);
  if(m_dispatchQueue.empty())
    return false;

  DispatchEventUnsafe(lk);
  return true;
}
<commit_msg>Fixed failing autowiring test<commit_after>// Copyright (c) 2010 - 2013 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "DispatchQueue.h"
#include "at_exit.h"

DispatchQueue::DispatchQueue(void):
  m_aborted(false),
  m_dispatchCap(1024)
{
  m_waitPredicate = [this] {
    if(m_aborted)
      throw dispatch_aborted_exception();
    return !m_dispatchQueue.empty() && m_dispatchQueue.front()->IsCommited();
  };
}

DispatchQueue::~DispatchQueue(void) {
  // Teardown:
  for(auto q = m_dispatchQueue.begin(); q != m_dispatchQueue.end(); q++)
    delete *q;
}

void DispatchQueue::Abort(void) {
  boost::lock_guard<boost::mutex> lk(m_dispatchLock);
  m_aborted = true;

  // Rip apart:
  for(auto q = m_dispatchQueue.begin(); q != m_dispatchQueue.end(); q++)
    delete *q;
  m_dispatchQueue.clear();

  // Wake up anyone who is still waiting:
  m_queueUpdated.notify_all();
}

void DispatchQueue::DispatchEventUnsafe(boost::unique_lock<boost::mutex>& lk) {
  DispatchThunkBase* thunk = m_dispatchQueue.front();
  m_dispatchQueue.pop_front();
  bool wasEmpty = m_dispatchQueue.empty();
  lk.unlock();

  auto generalCleanup = MakeAtExit(
    [this, thunk, wasEmpty] {
      delete thunk;

      // If we emptied the queue, we'd like to reobtain the lock and tell everyone
      // that the queue is now empty.
      if(wasEmpty)
        m_queueUpdated.notify_all();
    }
  );

  (*thunk)();
}

void DispatchQueue::WaitForEvent(void) {
  boost::unique_lock<boost::mutex> lk(m_dispatchLock);
  if(m_aborted)
    throw dispatch_aborted_exception();

  m_queueUpdated.wait(lk, m_waitPredicate);
  DispatchEventUnsafe(lk);
}

bool DispatchQueue::WaitForEvent(boost::chrono::duration<double, boost::milli> milliseconds) {
  boost::unique_lock<boost::mutex> lk(m_dispatchLock);
  if(m_aborted)
    throw dispatch_aborted_exception();

  m_queueUpdated.wait_for(lk, milliseconds, m_waitPredicate);
  if(m_dispatchQueue.empty())
    return false;

  DispatchEventUnsafe(lk);
  return true;
}

bool DispatchQueue::WaitForEvent(boost::chrono::steady_clock::time_point wakeTime) {
  if(wakeTime == boost::chrono::steady_clock::time_point::max())
    // Maximal wait--we can optimize by using the zero-arguments version
    return WaitForEvent(), true;

  boost::unique_lock<boost::mutex> lk(m_dispatchLock);
  if(m_aborted)
    throw dispatch_aborted_exception();

  m_queueUpdated.wait_until(lk, wakeTime, m_waitPredicate);
  if(m_dispatchQueue.empty())
    return false;

  DispatchEventUnsafe(lk);
  return true;
}

bool DispatchQueue::DispatchEvent(void) {
  boost::unique_lock<boost::mutex> lk(m_dispatchLock);
  if(m_dispatchQueue.empty() || !m_dispatchQueue.front()->IsCommited())
    return false;

  DispatchEventUnsafe(lk);
  return true;
}
<|endoftext|>


<commit_before>#include "LIBGPU.H"

#include "EMULATOR.H"

#define GL_GLEXT_PROTOTYPES 1
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_opengl_glext.h>

#include <stdio.h>
#include <cstring>
#include <cassert>
#include <LIBETC.H>

unsigned short vram[1024 * 512];
DISPENV word_33BC;
int dword_3410 = 0;
char byte_3352 = 0;

void* off_3348[]=
{
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL
};

int ClearImage(RECT16* rect, u_char r, u_char g, u_char b)
{
	for (int y = rect->y; y < 512; y++)
	{
		for (int x = rect->x; x < 1024; x++)
		{
			unsigned short* pixel = vram + (y * 1024 + x);

			if (x >= rect->x && x < rect->x + rect->w &&
				y >= rect->y && y < rect->y + rect->h)
			{
				pixel[0] = ((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 1) | 0;
			}
		}
	}

	return 0;
}

int DrawSync(int mode)
{
	return 0;
}

int LoadImagePSX(RECT16* rect, u_long* p)
{
	unsigned short* dst = (unsigned short*)p;

	for (int y = rect->y; y < 512; y++)
	{
		for (int x = rect->x; x < 1024; x++)
		{
			unsigned short* src = vram + (y * 1024 + x);

			if (x >= rect->x && x < rect->x + rect->w &&
				y >= rect->y && y < rect->y + rect->h)
			{
				src[0] = *dst++;
			}
		}
	}

#if _DEBUG
	FILE* f = fopen("VRAM.BIN", "wb");
	fwrite(&vram[0], 1, 1024 * 512 * 2, f);
	fclose(f);
#endif

	return 0;
}

int ResetGraph(int mode)
{
	return 0;
}

int SetGraphDebug(int level)
{
	return 0;
}

int StoreImage(RECT16 * RECT16, u_long * p)
{
	return 0;
}

u_long * ClearOTag(u_long * ot, int n)
{
	assert(0);
	return 0;
}

u_long* ClearOTagR(u_long* ot, int n)
{
	//v0 = byte_3352;
	//s0 = ot
	//s1 = n

	//v0 = v0 < 2 ? 1 : 0
	if (byte_3352 > 1)
	{
		///GPU_printf("ClearOTagR(%08x,%d)...\n", ot, n);
	}

	//loc_CB0
//	((void*)off_3348[11])();

	return 0;
}

void SetDispMask(int mask)
{
}

DISPENV* GetDispEnv(DISPENV* env)//(F)
{
	memcpy(env, &word_33BC, sizeof(DISPENV));
	return env;
}

DISPENV* PutDispEnv(DISPENV* env)//To Finish
{
	memcpy((char*)&word_33BC, env, sizeof(DISPENV));
	return 0;
}

DISPENV* SetDefDispEnv(DISPENV* env, int x, int y, int w, int h)//(F)
{
	env->disp.x = x;
	env->disp.y = y;
	env->disp.w = w;
	env->screen.x = 0;
	env->screen.y = 0;
	env->screen.w = 0;
	env->screen.h = 0;
	env->isrgb24 = 0;
	env->isinter = 0;
	env->pad1 = 0;
	env->pad0 = 0;
	env->disp.h = h;
	return 0;
}

DRAWENV* PutDrawEnv(DRAWENV* env)
{
	return NULL;
}

DRAWENV* SetDefDrawEnv(DRAWENV* env, int x, int y, int w, int h)//(F)
{
	env->clip.x = x;
	env->clip.y = y;
	env->clip.w = w;
	env->tw.x = 0;
	env->tw.y = 0;
	env->tw.w = 0;
	env->tw.h = 0;
	env->r0 = 0;
	env->g0 = 0;
	env->b0 = 0;
	env->dtd = 1;
	env->clip.h = h;

	if (GetVideoMode() == 0)
	{
		env->dfe = h < 0x121 ? 1 : 0;
	}
	else
	{
		env->dfe = h < 0x101 ? 1 : 0;
	}

	env->ofs[0] = x;
	env->ofs[1] = y;

	env->tpage = 10;
	env->isbg = 0;

	return env;
}

u_long DrawSyncCallback(void(*func)(void))
{

	return u_long();
}

void DrawOTagEnv(u_long* p, DRAWENV* env)
{
	printf("Debug");
}
<commit_msg>ClearImage correct argb values. Fixes transparency.<commit_after>#include "LIBGPU.H"

#include "EMULATOR.H"

#define GL_GLEXT_PROTOTYPES 1
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_opengl_glext.h>

#include <stdio.h>
#include <cstring>
#include <cassert>
#include <LIBETC.H>

unsigned short vram[1024 * 512];
DISPENV word_33BC;
int dword_3410 = 0;
char byte_3352 = 0;

void* off_3348[]=
{
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL
};

int ClearImage(RECT16* rect, u_char r, u_char g, u_char b)
{
	for (int y = rect->y; y < 512; y++)
	{
		for (int x = rect->x; x < 1024; x++)
		{
			unsigned short* pixel = vram + (y * 1024 + x);

			if (x >= rect->x && x < rect->x + rect->w &&
				y >= rect->y && y < rect->y + rect->h)
			{
				pixel[0] = 1 << 15 | ((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3));
			}
		}
	}

	return 0;
}

int DrawSync(int mode)
{
	return 0;
}

int LoadImagePSX(RECT16* rect, u_long* p)
{
	unsigned short* dst = (unsigned short*)p;

	for (int y = rect->y; y < 512; y++)
	{
		for (int x = rect->x; x < 1024; x++)
		{
			unsigned short* src = vram + (y * 1024 + x);

			if (x >= rect->x && x < rect->x + rect->w &&
				y >= rect->y && y < rect->y + rect->h)
			{
				src[0] = *dst++;

				//pixel[0] = 1 << 15 | ((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3));
			}
		}
	}

#if _DEBUG
	FILE* f = fopen("VRAM.BIN", "wb");
	fwrite(&vram[0], 1, 1024 * 512 * 2, f);
	fclose(f);
#endif

	return 0;
}

int ResetGraph(int mode)
{
	return 0;
}

int SetGraphDebug(int level)
{
	return 0;
}

int StoreImage(RECT16 * RECT16, u_long * p)
{
	return 0;
}

u_long * ClearOTag(u_long * ot, int n)
{
	assert(0);
	return 0;
}

u_long* ClearOTagR(u_long* ot, int n)
{
	//v0 = byte_3352;
	//s0 = ot
	//s1 = n

	//v0 = v0 < 2 ? 1 : 0
	if (byte_3352 > 1)
	{
		///GPU_printf("ClearOTagR(%08x,%d)...\n", ot, n);
	}

	//loc_CB0
//	((void*)off_3348[11])();

	return 0;
}

void SetDispMask(int mask)
{
}

DISPENV* GetDispEnv(DISPENV* env)//(F)
{
	memcpy(env, &word_33BC, sizeof(DISPENV));
	return env;
}

DISPENV* PutDispEnv(DISPENV* env)//To Finish
{
	memcpy((char*)&word_33BC, env, sizeof(DISPENV));
	return 0;
}

DISPENV* SetDefDispEnv(DISPENV* env, int x, int y, int w, int h)//(F)
{
	env->disp.x = x;
	env->disp.y = y;
	env->disp.w = w;
	env->screen.x = 0;
	env->screen.y = 0;
	env->screen.w = 0;
	env->screen.h = 0;
	env->isrgb24 = 0;
	env->isinter = 0;
	env->pad1 = 0;
	env->pad0 = 0;
	env->disp.h = h;
	return 0;
}

DRAWENV* PutDrawEnv(DRAWENV* env)
{
	return NULL;
}

DRAWENV* SetDefDrawEnv(DRAWENV* env, int x, int y, int w, int h)//(F)
{
	env->clip.x = x;
	env->clip.y = y;
	env->clip.w = w;
	env->tw.x = 0;
	env->tw.y = 0;
	env->tw.w = 0;
	env->tw.h = 0;
	env->r0 = 0;
	env->g0 = 0;
	env->b0 = 0;
	env->dtd = 1;
	env->clip.h = h;

	if (GetVideoMode() == 0)
	{
		env->dfe = h < 0x121 ? 1 : 0;
	}
	else
	{
		env->dfe = h < 0x101 ? 1 : 0;
	}

	env->ofs[0] = x;
	env->ofs[1] = y;

	env->tpage = 10;
	env->isbg = 0;

	return env;
}

u_long DrawSyncCallback(void(*func)(void))
{

	return u_long();
}

void DrawOTagEnv(u_long* p, DRAWENV* env)
{
	printf("Debug");
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008, 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QtTest/QtTest>
#include <QtCore>
#include "contextpropertyinfo.h"
#include "infobackend.h"

QMap <QString, QString> constructionStringMap;
QMap <QString, QString> typeMap;
QMap <QString, QString> docMap;
QMap <QString, QString> pluginMap;
QMap <QString, bool> providedMap;

/* Mocked infobackend */

InfoBackend* currentBackend = NULL;

InfoBackend* InfoBackend::instance(const QString &backendName)
{
    if (currentBackend)
        return currentBackend;
    else {
        currentBackend = new InfoBackend();
        return currentBackend;
    }
}

QString InfoBackend::constructionStringForKey(QString key) const
{
    if (constructionStringMap.contains(key))
        return constructionStringMap.value(key);
    else
        return QString();
}

QString InfoBackend::typeForKey(QString key) const
{
     if (typeMap.contains(key))
        return typeMap.value(key);
    else
        return QString();
}

QString InfoBackend::docForKey(QString key) const
{
    if (docMap.contains(key))
        return docMap.value(key);
    else
        return QString();
}

QString InfoBackend::pluginForKey(QString key) const
{
    if (pluginMap.contains(key))
        return pluginMap.value(key);
    else
        return QString();
}

bool InfoBackend::keyExists(QString key) const
{
    if (typeMap.contains(key))
        return true;
    else
        return false;
}

bool InfoBackend::keyProvided(QString key) const
{
    if (providedMap.contains(key))
        return providedMap.value(key);
    else
        return false;
}

void InfoBackend::connectNotify(const char *signal)
{
}

void InfoBackend::disconnectNotify(const char *signal)
{
}

void InfoBackend::fireKeysChanged(const QStringList& keys)
{
    emit keysChanged(keys);
}

void InfoBackend::fireKeysAdded(const QStringList& keys)
{
    emit keysAdded(keys);
}

void InfoBackend::fireKeysRemoved(const QStringList& keys)
{
    emit keysRemoved(keys);
}

void InfoBackend::fireKeyDataChanged(const QString& key)
{
    emit keyDataChanged(key);
}

/* ContextRegistryInfoUnitTest */

class ContextPropertyInfoUnitTest : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void key();
    void doc();
    void type();
    void exists();
    void provided();
    void providerDBusName();
    void providerDBusType();
    void plugin();
    void constructionString();
    void typeChanged();
};

void ContextPropertyInfoUnitTest::initTestCase()
{
    constructionStringMap.clear();
    constructionStringMap.insert("Battery.Charging", "system:org.freedesktop.ContextKit.contextd");
    constructionStringMap.insert("Media.NowPlaying", "session:com.nokia.musicplayer");

    typeMap.clear();
    typeMap.insert("Battery.Charging", "TRUTH");
    typeMap.insert("Media.NowPlaying", "STRING");

    docMap.clear();
    docMap.insert("Battery.Charging", "Battery.Charging doc");
    docMap.insert("Media.NowPlaying", "Media.NowPlaying doc");

    pluginMap.clear();
    pluginMap.insert("Battery.Charging", "contextkit-dbus");
    pluginMap.insert("Media.NowPlaying", "contextkit-dbus");

    providedMap.clear();
    providedMap.insert("Battery.Charging", true);
    providedMap.insert("Media.NowPlaying", true);
}

void ContextPropertyInfoUnitTest::key()
{
    ContextPropertyInfo p("Battery.Charging");
    QCOMPARE(p.key(), QString("Battery.Charging"));
}

void ContextPropertyInfoUnitTest::doc()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.doc(), QString("Battery.Charging doc"));
    QCOMPARE(p2.doc(), QString("Media.NowPlaying doc"));
    QCOMPARE(p3.doc(), QString());
}

void ContextPropertyInfoUnitTest::type()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.type(), QString("TRUTH"));
    QCOMPARE(p2.type(), QString("STRING"));
    QCOMPARE(p3.type(), QString());
}

void ContextPropertyInfoUnitTest::exists()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.exists(), true);
    QCOMPARE(p2.exists(), true);
    QCOMPARE(p3.exists(), false);
}

void ContextPropertyInfoUnitTest::provided()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.provided(), true);
    QCOMPARE(p2.provided(), true);
    QCOMPARE(p3.provided(), false);
}

void ContextPropertyInfoUnitTest::providerDBusName()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.providerDBusName(), QString("org.freedesktop.ContextKit.contextd"));
    QCOMPARE(p2.providerDBusName(), QString("com.nokia.musicplayer"));
    QCOMPARE(p3.providerDBusName(), QString());
}

void ContextPropertyInfoUnitTest::providerDBusType()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.providerDBusType(), QDBusConnection::SystemBus);
    QCOMPARE(p2.providerDBusType(), QDBusConnection::SessionBus);
    QCOMPARE(p3.providerDBusType(), QDBusConnection::SessionBus);
}

void ContextPropertyInfoUnitTest::plugin()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.plugin(), QString("contextkit-dbus"));
    QCOMPARE(p2.plugin(), QString("contextkit-dbus"));
    QCOMPARE(p3.plugin(), QString());
}

void ContextPropertyInfoUnitTest::constructionString()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.constructionString(), QString("system:org.freedesktop.ContextKit.contextd"));
    QCOMPARE(p2.constructionString(), QString("session:com.nokia.musicplayer"));
    QCOMPARE(p3.constructionString(), QString());
}

void ContextPropertyInfoUnitTest::typeChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(typeChanged(QString)));

    currentBackend->fireKeyDataChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 0);

    typeMap.insert("Battery.Charging", "INT");
    currentBackend->fireKeyDataChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toString(), QString("INT"));
}

#include "contextpropertyinfounittest.moc"
QTEST_MAIN(ContextPropertyInfoUnitTest);
<commit_msg>providerChanged.<commit_after>/*
 * Copyright (C) 2008, 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QtTest/QtTest>
#include <QtCore>
#include "contextpropertyinfo.h"
#include "infobackend.h"

QMap <QString, QString> constructionStringMap;
QMap <QString, QString> typeMap;
QMap <QString, QString> docMap;
QMap <QString, QString> pluginMap;
QMap <QString, bool> providedMap;

/* Mocked infobackend */

InfoBackend* currentBackend = NULL;

InfoBackend* InfoBackend::instance(const QString &backendName)
{
    if (currentBackend)
        return currentBackend;
    else {
        currentBackend = new InfoBackend();
        return currentBackend;
    }
}

QString InfoBackend::constructionStringForKey(QString key) const
{
    if (constructionStringMap.contains(key))
        return constructionStringMap.value(key);
    else
        return QString();
}

QString InfoBackend::typeForKey(QString key) const
{
     if (typeMap.contains(key))
        return typeMap.value(key);
    else
        return QString();
}

QString InfoBackend::docForKey(QString key) const
{
    if (docMap.contains(key))
        return docMap.value(key);
    else
        return QString();
}

QString InfoBackend::pluginForKey(QString key) const
{
    if (pluginMap.contains(key))
        return pluginMap.value(key);
    else
        return QString();
}

bool InfoBackend::keyExists(QString key) const
{
    if (typeMap.contains(key))
        return true;
    else
        return false;
}

bool InfoBackend::keyProvided(QString key) const
{
    if (providedMap.contains(key))
        return providedMap.value(key);
    else
        return false;
}

void InfoBackend::connectNotify(const char *signal)
{
}

void InfoBackend::disconnectNotify(const char *signal)
{
}

void InfoBackend::fireKeysChanged(const QStringList& keys)
{
    emit keysChanged(keys);
}

void InfoBackend::fireKeysAdded(const QStringList& keys)
{
    emit keysAdded(keys);
}

void InfoBackend::fireKeysRemoved(const QStringList& keys)
{
    emit keysRemoved(keys);
}

void InfoBackend::fireKeyDataChanged(const QString& key)
{
    emit keyDataChanged(key);
}

/* ContextRegistryInfoUnitTest */

class ContextPropertyInfoUnitTest : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void key();
    void doc();
    void type();
    void exists();
    void provided();
    void providerDBusName();
    void providerDBusType();
    void plugin();
    void constructionString();
    void typeChanged();
    void providerChanged();
};

void ContextPropertyInfoUnitTest::initTestCase()
{
    constructionStringMap.clear();
    constructionStringMap.insert("Battery.Charging", "system:org.freedesktop.ContextKit.contextd");
    constructionStringMap.insert("Media.NowPlaying", "session:com.nokia.musicplayer");

    typeMap.clear();
    typeMap.insert("Battery.Charging", "TRUTH");
    typeMap.insert("Media.NowPlaying", "STRING");

    docMap.clear();
    docMap.insert("Battery.Charging", "Battery.Charging doc");
    docMap.insert("Media.NowPlaying", "Media.NowPlaying doc");

    pluginMap.clear();
    pluginMap.insert("Battery.Charging", "contextkit-dbus");
    pluginMap.insert("Media.NowPlaying", "contextkit-dbus");

    providedMap.clear();
    providedMap.insert("Battery.Charging", true);
    providedMap.insert("Media.NowPlaying", true);
}

void ContextPropertyInfoUnitTest::key()
{
    ContextPropertyInfo p("Battery.Charging");
    QCOMPARE(p.key(), QString("Battery.Charging"));
}

void ContextPropertyInfoUnitTest::doc()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.doc(), QString("Battery.Charging doc"));
    QCOMPARE(p2.doc(), QString("Media.NowPlaying doc"));
    QCOMPARE(p3.doc(), QString());
}

void ContextPropertyInfoUnitTest::type()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.type(), QString("TRUTH"));
    QCOMPARE(p2.type(), QString("STRING"));
    QCOMPARE(p3.type(), QString());
}

void ContextPropertyInfoUnitTest::exists()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.exists(), true);
    QCOMPARE(p2.exists(), true);
    QCOMPARE(p3.exists(), false);
}

void ContextPropertyInfoUnitTest::provided()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.provided(), true);
    QCOMPARE(p2.provided(), true);
    QCOMPARE(p3.provided(), false);
}

void ContextPropertyInfoUnitTest::providerDBusName()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.providerDBusName(), QString("org.freedesktop.ContextKit.contextd"));
    QCOMPARE(p2.providerDBusName(), QString("com.nokia.musicplayer"));
    QCOMPARE(p3.providerDBusName(), QString());
}

void ContextPropertyInfoUnitTest::providerDBusType()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.providerDBusType(), QDBusConnection::SystemBus);
    QCOMPARE(p2.providerDBusType(), QDBusConnection::SessionBus);
    QCOMPARE(p3.providerDBusType(), QDBusConnection::SessionBus);
}

void ContextPropertyInfoUnitTest::plugin()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.plugin(), QString("contextkit-dbus"));
    QCOMPARE(p2.plugin(), QString("contextkit-dbus"));
    QCOMPARE(p3.plugin(), QString());
}

void ContextPropertyInfoUnitTest::constructionString()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.constructionString(), QString("system:org.freedesktop.ContextKit.contextd"));
    QCOMPARE(p2.constructionString(), QString("session:com.nokia.musicplayer"));
    QCOMPARE(p3.constructionString(), QString());
}

void ContextPropertyInfoUnitTest::typeChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(typeChanged(QString)));

    currentBackend->fireKeyDataChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 0);

    typeMap.insert("Battery.Charging", "INT");
    currentBackend->fireKeyDataChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toString(), QString("INT"));
}

void ContextPropertyInfoUnitTest::providerChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(providerChanged(QString)));

    currentBackend->fireKeyDataChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 0);

    constructionStringMap.insert("Battery.Charging", "system:org.freedesktop.ContextKit.robot");
    currentBackend->fireKeyDataChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toString(), QString("org.freedesktop.ContextKit.robot"));
}

#include "contextpropertyinfounittest.moc"
QTEST_MAIN(ContextPropertyInfoUnitTest);
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <iostream>
#include <sstream>
#include <tuple>

/* TODO
    All char types to be handled correctly.
    More succint dispatch for char types, possibly SFINAE-based.
    Principled, typeclass-like way to extend show.
*/

namespace show{

    template<typename T>
    std::string show(const T& t);

    namespace _dtl {

        template<typename T>
        constexpr bool expand_to_false(){return false;}

        template<std::size_t> struct Nat{};
        template<typename...> struct TypeList{};

        template<typename T> using IsIterable =
            TypeList<decltype(std::begin(T{})),
                     decltype(std::end(T{})),
                     decltype(++std::begin(T{})),
                     decltype(*std::begin(T{})),
                     decltype(std::begin(T{}) != std::end(T{}))>;

        template<typename T> using IsTrivial =
            decltype(std::stringstream{}.operator<<(T{}));

        struct Iterable;
        struct Trivial;
        struct Undefined;
        struct Tuple;
        struct Pair;
        struct String;
        struct Char;

        template<typename T>
        struct GetFormat{
            template<typename, typename = IsTrivial<T>>  static Trivial   check(void*);
            template<typename, typename = IsIterable<T>> static Iterable  check(void*);
            template<typename>                           static Undefined check(...);
            using type = decltype(check<T>(nullptr));
        };

        template<typename A, typename B>
        struct GetFormat<std::pair<A, B>> {using type = Pair;};

        template<typename... TS>
        struct GetFormat<std::tuple<TS...>> {using type = Tuple;};

        template<typename C, typename T, typename A>
        struct GetFormat<std::basic_string<C, T, A>> {using type = String;};

        template<typename T, size_t N>
        struct GetFormat<T[N]> {using type = Iterable;};

        template<size_t N> struct GetFormat<char[N]>     {using type = String;};
        template<>         struct GetFormat<const char*> {using type = String;};
        template<>         struct GetFormat<char*>       {using type = String;};
        template<>         struct GetFormat<char>        {using type = Char;};

        struct Iterable{
            template<typename T>
            std::string operator()(const T& t){
                std::string res{};
                auto it = std::begin(t);
                auto finish = std::end(t);
                res += "[";
                if (it != finish){
                    res += show(*it);
                    ++it;
                    for (;it != finish; ++it){
                        res += ", ";
                        res += show(*it);
                    }
                }
                res += "]";
                return res;
            }
        };

        struct Trivial{
            template<typename T>
            std::string operator()(const T& t){
                std::stringstream fmt{};
                fmt.operator<<(t);
                return fmt.str();
            }
        };

        struct String{
            template<typename T>
            std::string operator()(const T& t){
                return "\"" + std::string(t) + "\"";
            }
        };

        struct Pair{
            template<typename A, typename B>
            std::string operator()(const std::pair<A, B>& p){
                return "(" + show(p.first) + ", " + show(p.second) + ")";
            }
        };

        struct Tuple{
            template <typename... TS>
            std::string operator()(const std::tuple<TS...>& tpl) {
                std::string res{};
                res += "(";
                helper(res, tpl, Nat<sizeof...(TS) - 1>{});
                res += ")";
                return res;
            }

            template<typename T, std::size_t N>
            void helper(std::string& res, const T &tpl, Nat<N>){
                helper(res, tpl, Nat<N-1>{});
                res += ", ";
                res += show(std::get<N>(tpl));
            }

            template<typename T>
            void helper(std::string& res, const T &tpl, Nat<0>){
                res += show(std::get<0>(tpl));
            }
        };

        struct Char{
            template<typename T>
            std::string operator()(const T& t){
                return std::string("'") + t + '\'';
            }
        };

        struct Undefined{
            template<typename T>
            std::string operator()(const T&){
                static_assert(expand_to_false<T>(), "Show undefined for type.");
                return "";
            }
        };

    } // namespace _dtl

    template<typename T>
    std::string show(const T& t){
        return typename _dtl::GetFormat<T>::type{}(t);
    }

    void print(){
        std::cout << std::endl;
    }

    template<typename T, typename... TS>
    void print(const T& t, const TS&... ts){
        std::cout << show(t) << ' ';
        print(ts...);
    }

} // namespace show

<commit_msg>fixed sfinae on dispatch<commit_after>#pragma once

#include <string>
#include <iostream>
#include <sstream>
#include <tuple>

/* TODO
    All char types to be handled correctly.
    More succint dispatch for char types, probably SFINAE-based.
*/

namespace show{

    template<typename T>
    std::string show(const T& t);

    namespace _dtl {

        template<typename T>
        constexpr bool expand_to_false(){return false;}

        template<std::size_t> struct Nat{};
        template<typename...> struct TypeList{};

        template<typename T> using IsIterable =
            TypeList<decltype(std::begin(T{})),
                     decltype(std::end(T{})),
                     decltype(++std::begin(T{})),
                     decltype(*std::begin(T{})),
                     decltype(std::begin(T{}) != std::end(T{}))>;

        template<typename T> using IsTrivial =
            decltype(std::stringstream{}.operator<<(T{}));

        struct Iterable;
        struct Trivial;
        struct Undefined;
        struct Tuple;
        struct Pair;
        struct String;
        struct Char;

        template<typename T>
        struct GetFormat{
            template<typename U, typename = IsTrivial<U>>  static Trivial   check(void*);
            template<typename U, typename = IsIterable<U>> static Iterable  check(void*);
            template<typename>                             static Undefined check(...);
            using type = decltype(check<T>(nullptr));
        };

        template<typename A, typename B>
        struct GetFormat<std::pair<A, B>> {using type = Pair;};

        template<typename... TS>
        struct GetFormat<std::tuple<TS...>> {using type = Tuple;};

        template<typename C, typename T, typename A>
        struct GetFormat<std::basic_string<C, T, A>> {using type = String;};

        template<typename T, size_t N>
        struct GetFormat<T[N]> {using type = Iterable;};

        template<size_t N> struct GetFormat<char[N]>     {using type = String;};
        template<>         struct GetFormat<const char*> {using type = String;};
        template<>         struct GetFormat<char*>       {using type = String;};
        template<>         struct GetFormat<char>        {using type = Char;};

        struct Iterable{
            template<typename T>
            std::string operator()(const T& t){
                std::string res{};
                auto it = std::begin(t);
                auto finish = std::end(t);
                res += "[";
                if (it != finish){
                    res += show(*it);
                    ++it;
                    for (;it != finish; ++it){
                        res += ", ";
                        res += show(*it);
                    }
                }
                res += "]";
                return res;
            }
        };

        struct Trivial{
            template<typename T>
            std::string operator()(const T& t){
                std::stringstream fmt{};
                fmt.operator<<(t);
                return fmt.str();
            }
        };

        struct String{
            template<typename T>
            std::string operator()(const T& t){
                return "\"" + std::string(t) + "\"";
            }
        };

        struct Pair{
            template<typename A, typename B>
            std::string operator()(const std::pair<A, B>& p){
                return "(" + show(p.first) + ", " + show(p.second) + ")";
            }
        };

        struct Tuple{
            template <typename... TS>
            std::string operator()(const std::tuple<TS...>& tpl) {
                std::string res{};
                res += "(";
                helper(res, tpl, Nat<sizeof...(TS) - 1>{});
                res += ")";
                return res;
            }

            template<typename T, std::size_t N>
            void helper(std::string& res, const T &tpl, Nat<N>){
                helper(res, tpl, Nat<N-1>{});
                res += ", ";
                res += show(std::get<N>(tpl));
            }

            template<typename T>
            void helper(std::string& res, const T &tpl, Nat<0>){
                res += show(std::get<0>(tpl));
            }
        };

        struct Char{
            template<typename T>
            std::string operator()(const T& t){
                return std::string("'") + t + '\'';
            }
        };

        struct Undefined{
            template<typename T>
            std::string operator()(const T&){
                static_assert(expand_to_false<T>(), "Show undefined for type.");
                return "";
            }
        };

    } // namespace _dtl

    template<typename T>
    std::string show(const T& t){
        return typename _dtl::GetFormat<T>::type{}(t);
    }

    void print(){
        std::cout << std::endl;
    }

    template<typename T, typename... TS>
    void print(const T& t, const TS&... ts){
        std::cout << show(t) << ' ';
        print(ts...);
    }

} // namespace show
<|endoftext|>


<commit_before>/* Copyright 2017 QReal Research Group
 *
 * 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. */

#include "pioneerLuaMasterGenerator.h"

#include <QtCore/QDir>

#include <qrkernel/logging.h>
#include <qrkernel/exception/exception.h>
#include <qrtext/languageToolboxInterface.h>
#include <qrutils/stringUtils.h>
#include <generatorBase/parts/initTerminateCodeGenerator.h>
#include <generatorBase/gotoControlFlowGenerator.h>
#include <generatorBase/parts/subprograms.h>
#include <generatorBase/parts/threads.h>
#include <generatorBase/parts/variables.h>

#include "pioneerLuaGeneratorCustomizer.h"
#include "pioneerLuaGeneratorFactory.h"
#include "generators/pioneerStateMachineGenerator.h"
#include "generators/gotoLabelManager.h"
#include "generators/randomFunctionChecker.h"

using namespace pioneer::lua;
using namespace generatorBase;

using namespace qReal;

PioneerLuaMasterGenerator::PioneerLuaMasterGenerator(const qrRepo::RepoApi &repo
		, qReal::ErrorReporterInterface &errorReporter
		, const utils::ParserErrorReporter &parserErrorReporter
		, const kitBase::robotModel::RobotModelManagerInterface &robotModelManager
		, qrtext::LanguageToolboxInterface &textLanguage
		, const qReal::Id &diagramId
		, const QString &generatorName
		, const qReal::EditorManagerInterface &metamodel)
	: MasterGeneratorBase(repo, errorReporter, robotModelManager, textLanguage, parserErrorReporter, diagramId)
	, mGeneratorName(generatorName)
	, mMetamodel(metamodel)
	, mGotoLabelManager(new GotoLabelManager())
{
}

PioneerLuaMasterGenerator::~PioneerLuaMasterGenerator()
{
	// Empty destructor to keep QScopedPointer happy.
}

void PioneerLuaMasterGenerator::initialize()
{
	MasterGeneratorBase::initialize();
	mControlFlowGenerator.reset(
			new PioneerStateMachineGenerator(mRepo, mErrorReporter, *mCustomizer, *mValidator, mDiagram)
			);

	auto factory = dynamic_cast<PioneerLuaGeneratorFactory *>(mCustomizer->factory());
	if (!factory) {
		throw qReal::Exception("PioneerLuaMasterGenerator shall work only with PioneerLuaGeneratorFactory");
	}

	mRandomFunctionChecker.reset(
			new RandomFunctionChecker(mRepo, mMetamodel, mTextLanguage, factory->randomGeneratorPart()));

	mControlFlowGenerator->registerNodeHook([this](const qReal::Id &id){ mRandomFunctionChecker->checkNode(id); });
}

generatorBase::GeneratorCustomizer *PioneerLuaMasterGenerator::createCustomizer()
{
	return new PioneerLuaGeneratorCustomizer(
			mRepo
			, mErrorReporter
			, mRobotModelManager
			, *createLuaProcessor()
			, mGeneratorName
			, *mGotoLabelManager);
}

QString PioneerLuaMasterGenerator::targetPath()
{
	return QString("%1/%2.lua").arg(mProjectDir, mProjectName);
}

bool PioneerLuaMasterGenerator::supportsGotoGeneration() const
{
	return true;
}

void PioneerLuaMasterGenerator::beforeGeneration()
{
	QDir().mkpath(mProjectDir + "/ap/");
	QDir().mkpath(mProjectDir + "/Ev/");
	QFile::copy(":/pioneer/lua/templates/testStub/ap/lua.lua", mProjectDir + "/ap/lua.lua");
	QFile::copy(":/pioneer/lua/templates/testStub/Ev/lua.lua", mProjectDir + "/Ev/lua.lua");
}

QString PioneerLuaMasterGenerator::generate(const QString &indentString)
{
	if (mDiagram.isNull()) {
		mErrorReporter.addCritical(QObject::tr("There is no opened diagram"));
		return QString();
	}

	QLOG_INFO() << "Starting Pioneer program generation to " << mProjectDir;

	mGotoLabelManager->reinit();

	beforeGeneration();

	if (!QDir(mProjectDir).exists()) {
		QDir().mkpath(mProjectDir);
	}

	mTextLanguage.clear();
	mCustomizer->factory()->setMainDiagramId(mDiagram);

	for (parts::InitTerminateCodeGenerator *generator : mCustomizer->factory()->initTerminateGenerators()) {
		generator->reinit();
	}

	QString mainCode;

	const semantics::SemanticTree *mainControlFlow = mControlFlowGenerator->generate();
	if (mainControlFlow) {
		mainCode = mainControlFlow->toString(0, indentString);
		const parts::Subprograms::GenerationResult subprogramsResult = mCustomizer->factory()
				->subprograms()->generate(mControlFlowGenerator.data(), indentString);
		if (subprogramsResult != parts::Subprograms::GenerationResult::success) {
			mainCode = QString();
		}
	}

	if (mainCode.isEmpty()) {
		const QString errorMessage = tr("Generation failed. Possible causes are internal error in generator or too "
				"complex program structure.");
		mErrorReporter.addError(errorMessage);
		return QString();
	}

	QString resultCode = readTemplate("main.t");
	replaceWithAutoIndent(resultCode, "@@SUBPROGRAMS_FORWARDING@@"
			, mCustomizer->factory()->subprograms()->forwardDeclarations());
	replaceWithAutoIndent(resultCode, "@@SUBPROGRAMS@@"
			, mCustomizer->factory()->subprograms()->implementations());
	replaceWithAutoIndent(resultCode, "@@THREADS_FORWARDING@@"
			, mCustomizer->factory()->threads().generateDeclarations());
	replaceWithAutoIndent(resultCode, "@@THREADS@@"
			, mCustomizer->factory()->threads().generateImplementations(indentString));
	replaceWithAutoIndent(resultCode, "@@MAIN_CODE@@", mainCode);
	replaceWithAutoIndent(resultCode, "@@INITHOOKS@@", mCustomizer->factory()->initCode());
	replaceWithAutoIndent(resultCode, "@@TERMINATEHOOKS@@", utils::StringUtils::addIndent(
			mCustomizer->factory()->terminateCode(), 1, indentString));
	replaceWithAutoIndent(resultCode, "@@USERISRHOOKS@@", utils::StringUtils::addIndent(
			mCustomizer->factory()->isrHooksCode(), 1, indentString));
	const QString constantsString = mCustomizer->factory()->variables()->generateConstantsString();
	const QString variablesString = mCustomizer->factory()->variables()->generateVariableString();

	if (resultCode.contains("@@CONSTANTS@@")) {
		replaceWithAutoIndent(resultCode, "@@CONSTANTS@@", constantsString);
		replaceWithAutoIndent(resultCode, "@@VARIABLES@@", variablesString);
	} else {
		replaceWithAutoIndent(resultCode, "@@VARIABLES@@", constantsString + "\n" + variablesString);
	}

	// This will remove too many empty lines
	resultCode.replace(QRegExp("\n(\n)+"), "\n\n");

	processGeneratedCode(resultCode);

	generateLinkingInfo(resultCode);

	const QString pathToOutput = targetPath();
	outputCode(pathToOutput, resultCode);

	afterGeneration();

	return pathToOutput;
}
<commit_msg>Removed leading line breaks<commit_after>/* Copyright 2017 QReal Research Group
 *
 * 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. */

#include "pioneerLuaMasterGenerator.h"

#include <QtCore/QDir>

#include <qrkernel/logging.h>
#include <qrkernel/exception/exception.h>
#include <qrtext/languageToolboxInterface.h>
#include <qrutils/stringUtils.h>
#include <generatorBase/parts/initTerminateCodeGenerator.h>
#include <generatorBase/gotoControlFlowGenerator.h>
#include <generatorBase/parts/subprograms.h>
#include <generatorBase/parts/threads.h>
#include <generatorBase/parts/variables.h>

#include "pioneerLuaGeneratorCustomizer.h"
#include "pioneerLuaGeneratorFactory.h"
#include "generators/pioneerStateMachineGenerator.h"
#include "generators/gotoLabelManager.h"
#include "generators/randomFunctionChecker.h"

using namespace pioneer::lua;
using namespace generatorBase;

using namespace qReal;

PioneerLuaMasterGenerator::PioneerLuaMasterGenerator(const qrRepo::RepoApi &repo
		, qReal::ErrorReporterInterface &errorReporter
		, const utils::ParserErrorReporter &parserErrorReporter
		, const kitBase::robotModel::RobotModelManagerInterface &robotModelManager
		, qrtext::LanguageToolboxInterface &textLanguage
		, const qReal::Id &diagramId
		, const QString &generatorName
		, const qReal::EditorManagerInterface &metamodel)
	: MasterGeneratorBase(repo, errorReporter, robotModelManager, textLanguage, parserErrorReporter, diagramId)
	, mGeneratorName(generatorName)
	, mMetamodel(metamodel)
	, mGotoLabelManager(new GotoLabelManager())
{
}

PioneerLuaMasterGenerator::~PioneerLuaMasterGenerator()
{
	// Empty destructor to keep QScopedPointer happy.
}

void PioneerLuaMasterGenerator::initialize()
{
	MasterGeneratorBase::initialize();
	mControlFlowGenerator.reset(
			new PioneerStateMachineGenerator(mRepo, mErrorReporter, *mCustomizer, *mValidator, mDiagram)
			);

	auto factory = dynamic_cast<PioneerLuaGeneratorFactory *>(mCustomizer->factory());
	if (!factory) {
		throw qReal::Exception("PioneerLuaMasterGenerator shall work only with PioneerLuaGeneratorFactory");
	}

	mRandomFunctionChecker.reset(
			new RandomFunctionChecker(mRepo, mMetamodel, mTextLanguage, factory->randomGeneratorPart()));

	mControlFlowGenerator->registerNodeHook([this](const qReal::Id &id){ mRandomFunctionChecker->checkNode(id); });
}

generatorBase::GeneratorCustomizer *PioneerLuaMasterGenerator::createCustomizer()
{
	return new PioneerLuaGeneratorCustomizer(
			mRepo
			, mErrorReporter
			, mRobotModelManager
			, *createLuaProcessor()
			, mGeneratorName
			, *mGotoLabelManager);
}

QString PioneerLuaMasterGenerator::targetPath()
{
	return QString("%1/%2.lua").arg(mProjectDir, mProjectName);
}

bool PioneerLuaMasterGenerator::supportsGotoGeneration() const
{
	return true;
}

void PioneerLuaMasterGenerator::beforeGeneration()
{
	QDir().mkpath(mProjectDir + "/ap/");
	QDir().mkpath(mProjectDir + "/Ev/");
	QFile::copy(":/pioneer/lua/templates/testStub/ap/lua.lua", mProjectDir + "/ap/lua.lua");
	QFile::copy(":/pioneer/lua/templates/testStub/Ev/lua.lua", mProjectDir + "/Ev/lua.lua");
}

QString PioneerLuaMasterGenerator::generate(const QString &indentString)
{
	if (mDiagram.isNull()) {
		mErrorReporter.addCritical(QObject::tr("There is no opened diagram"));
		return QString();
	}

	QLOG_INFO() << "Starting Pioneer program generation to " << mProjectDir;

	mGotoLabelManager->reinit();

	beforeGeneration();

	if (!QDir(mProjectDir).exists()) {
		QDir().mkpath(mProjectDir);
	}

	mTextLanguage.clear();
	mCustomizer->factory()->setMainDiagramId(mDiagram);

	for (parts::InitTerminateCodeGenerator *generator : mCustomizer->factory()->initTerminateGenerators()) {
		generator->reinit();
	}

	QString mainCode;

	const semantics::SemanticTree *mainControlFlow = mControlFlowGenerator->generate();
	if (mainControlFlow) {
		mainCode = mainControlFlow->toString(0, indentString);
		const parts::Subprograms::GenerationResult subprogramsResult = mCustomizer->factory()
				->subprograms()->generate(mControlFlowGenerator.data(), indentString);
		if (subprogramsResult != parts::Subprograms::GenerationResult::success) {
			mainCode = QString();
		}
	}

	if (mainCode.isEmpty()) {
		const QString errorMessage = tr("Generation failed. Possible causes are internal error in generator or too "
				"complex program structure.");
		mErrorReporter.addError(errorMessage);
		return QString();
	}

	QString resultCode = readTemplate("main.t");
	replaceWithAutoIndent(resultCode, "@@SUBPROGRAMS_FORWARDING@@"
			, mCustomizer->factory()->subprograms()->forwardDeclarations());
	replaceWithAutoIndent(resultCode, "@@SUBPROGRAMS@@"
			, mCustomizer->factory()->subprograms()->implementations());
	replaceWithAutoIndent(resultCode, "@@THREADS_FORWARDING@@"
			, mCustomizer->factory()->threads().generateDeclarations());
	replaceWithAutoIndent(resultCode, "@@THREADS@@"
			, mCustomizer->factory()->threads().generateImplementations(indentString));
	replaceWithAutoIndent(resultCode, "@@MAIN_CODE@@", mainCode);
	replaceWithAutoIndent(resultCode, "@@INITHOOKS@@", mCustomizer->factory()->initCode());
	replaceWithAutoIndent(resultCode, "@@TERMINATEHOOKS@@", utils::StringUtils::addIndent(
			mCustomizer->factory()->terminateCode(), 1, indentString));
	replaceWithAutoIndent(resultCode, "@@USERISRHOOKS@@", utils::StringUtils::addIndent(
			mCustomizer->factory()->isrHooksCode(), 1, indentString));
	const QString constantsString = mCustomizer->factory()->variables()->generateConstantsString();
	const QString variablesString = mCustomizer->factory()->variables()->generateVariableString();

	if (resultCode.contains("@@CONSTANTS@@")) {
		replaceWithAutoIndent(resultCode, "@@CONSTANTS@@", constantsString);
		replaceWithAutoIndent(resultCode, "@@VARIABLES@@", variablesString);
	} else {
		replaceWithAutoIndent(resultCode, "@@VARIABLES@@", constantsString + "\n" + variablesString);
	}

	// This will remove too many empty lines
	resultCode.replace(QRegExp("\n(\n)+"), "\n\n");

	// This will remove leading and trailing whitespaces, line breaks and other unneeded stuff.
	resultCode = resultCode.trimmed();

	processGeneratedCode(resultCode);

	generateLinkingInfo(resultCode);

	const QString pathToOutput = targetPath();
	outputCode(pathToOutput, resultCode);

	afterGeneration();

	return pathToOutput;
}
<|endoftext|>