<commit_before>#pragma comment(lib,"opengl32")
#define _USE_MATH_DEFINES
#include <GL\glew.h>
#include <Windows.h>
#include <CaveLib\texture.h>
#include <CaveLib\model.h>
#include "App.h"
#include <glm/gtc/type_ptr.hpp>
#include <functional>

App::App(WiiMoteWrapper* w)
{
	wiiMoteWrapper = w;
}
App::~App(void){
	glUseProgram(0);
	glDeleteTextures(1, &fbo.fboTextureID);
	glDeleteTextures(1, &fbo.rboTextureID);
	glDeleteFramebuffers(1, &fbo.fboID);
	glDeleteRenderbuffers(1, &fbo.rboID);
}

void App::init(void)
{
	screenSize = glm::vec2(Kernel::getInstance()->getWindowWidth(), Kernel::getInstance()->getWindowHeight());
	m_pDebugDrawer = new DebugDrawer();
	m_pDebugDrawer->setDebugMode(3);
	headDevice.init("MainUserHead");
	cameraDevice.init("CameraPosition");
	physics.bullet3Init();
	cube_model = CaveLib::loadModel("data/aerial-pace-vr/models/cube.obj", new ModelLoadOptions(300.0f));
	checkers_model = CaveLib::loadModel("data/aerial-pace-vr/models/checkers_sphere.obj", new ModelLoadOptions(10.0f));
	sun_model = CaveLib::loadModel("data/aerial-pace-vr/models/checkers_sphere.obj", new ModelLoadOptions(10.0f));
	racetrack_model = CaveLib::loadModel("data/aerial-pace-vr/models/racetrack.obj", new ModelLoadOptions(100.0f));
	normals_texture = CaveLib::loadTexture("data/aerial-pace-vr/textures/normalmap3a.png", new TextureLoadOptions(GL_FALSE));
	pointLight.position = glm::vec3(60.0f, 20.0f, -10.0f);
	pointLight.intensities = glm::vec3(1.0f, 1.0f, 1.0f);
	pointLight.ambientCoefficient = 0.6f;
	pointLight.attentuation = 0.2f;
	physics.addFloor(racetrack_model);

	simpleShader = new ShaderProgram("data/aerial-pace-vr/shaders/simple.vert", "data/aerial-pace-vr/shaders/simple.frag");
	simpleShader->link();

	noiseShader = new ShaderProgram("data/aerial-pace-vr/shaders/perlinnoise.vert", "data/aerial-pace-vr/shaders/perlinnoise.frag");
	noiseShader->link();

	sunShader = new ShaderProgram("data/aerial-pace-vr/shaders/sunshader.vert", "data/aerial-pace-vr/shaders/sunshader.frag");
	sunShader->link();

	airnoiseShader = new ShaderProgram("data/aerial-pace-vr/shaders/airnoise.vert", "data/aerial-pace-vr/shaders/airnoise.frag");
	airnoiseShader->link();

	std::vector<string> shaders;
	shaders.push_back("normalpostprocess");
	shaders.push_back("blur");
	//shaders.push_back("threshold");
	shaders.push_back("mirror1");
	shaders.push_back("mirror2");
	shaders.push_back("mirror3");
	//shaders.push_back("draaien");
	shaders.push_back("shining");

	for each (string shader in shaders)
		fbo.fboShaders.push_back(new ShaderProgram("data/aerial-pace-vr/shaders/fbo/"+shader+".vert", "data/aerial-pace-vr/shaders/fbo/"+shader+".frag"));
	for each (ShaderProgram* program in fbo.fboShaders)
	{
		program->link();
		program->setUniformInt("s_texture", 0);
	}

	physics.world->setDebugDrawer(m_pDebugDrawer);

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);

	//fbo
	glGenTextures(1, &fbo.fboID);
	glBindTexture(GL_TEXTURE_2D, fbo.fboTextureID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glGenFramebuffers(1, &fbo.fboID);
	glBindFramebuffer(GL_FRAMEBUFFER, fbo.fboID);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenSize.x, screenSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.fboTextureID, 0);
	glGenRenderbuffers(1, &fbo.rboID);
	glGenTextures(1, &fbo.rboTextureID);
	glBindTexture(1, fbo.rboTextureID);
	glBindRenderbuffer(GL_RENDERBUFFER, fbo.rboID);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenSize.x, screenSize.y);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo.rboID);
	//auto b = glewGetErrorString(glGetError());
	GLenum e = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
	if (e != GL_FRAMEBUFFER_COMPLETE)
		printf("There is a problem with the FBO\n");
}

void App::preFrame(double frameTime, double totalTime)
{
	// timer
	clock_t clock_end = clock();
	GLfloat timeFctr = GLfloat(clock_end - clock_start) / CLOCKS_PER_SEC; // calculate time(s) elapsed since last frame
	fps = int(1 / timeFctr);
	clock_start = clock();
	if (GetAsyncKeyState(82) != 0){
		//physics.addCar();
	}

	if (GetAsyncKeyState(VK_RIGHT)){
		if (nextTimeToCheck < clock()){
			fbo.currentShader++;
			fbo.currentShader %= fbo.fboShaders.size();
			nextTimeToCheck = clock() + 130;
		}
	}

	if (GetAsyncKeyState(VK_LEFT)){
		if (nextTimeToCheck < clock()){
			fbo.currentShader--;
			if (fbo.currentShader == -1)
				fbo.currentShader = fbo.fboShaders.size() - 1;
			nextTimeToCheck = clock() + 130;
		}
	}

	//Check I
	if (GetAsyncKeyState(73) != 0)
	{
		//wiiMoteWrapper->buttonOne = true;
	}
	else
		//wiiMoteWrapper->buttonOne = false;
	//Check J
	if (GetAsyncKeyState(74) != 0)
	{
		//wiiMoteWrapper->degrees = -30;
	}
	//Check K
	if (GetAsyncKeyState(75) != 0)
	{
		//wiiMoteWrapper->buttonTwo = true;
	}
	else
		//wiiMoteWrapper->buttonTwo = false;
	//Check L
	if (GetAsyncKeyState(76) != 0)
	{
		//wiiMoteWrapper->degrees = 30;
	}
	if (GetAsyncKeyState(74) == 0 && GetAsyncKeyState(76) == 0)
		//wiiMoteWrapper->degrees = 0;
	physics.updateCar(timeFctr,wiiMoteWrapper);
}

void App::draw(const glm::mat4 &projectionMatrix, const glm::mat4 &modelViewMatrix)
{
	glBindFramebuffer(GL_FRAMEBUFFER, fbo.fboID);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_COLOR_MATERIAL);

	float mvpRaw[16];
	physics.realCar->getWorldTransform().getOpenGLMatrix(mvpRaw);

	// Car
	btVector3 carTranslation = physics.realCar->getWorldTransform().getOrigin();
	glm::vec3 cameraPosition(0, 0, 10.0f);
	glm::vec3 glmCarTranslation(-carTranslation.x(), -carTranslation.y() - 2, -carTranslation.z());

	// Devices
	glm::mat4 headData = headDevice.getData();
	glm::mat4 viewMatrix = modelViewMatrix * headData;

	// Update the uniform time variable.
	GLfloat time = GLfloat(clock()) / GLfloat(CLOCKS_PER_SEC);

	// Mvp
	glm::mat4 mvp = projectionMatrix * viewMatrix; // glm::mat4 mvp = projectionMatrix * modelViewMatrix;
	mvp = glm::rotate(mvp, -physics.realCar->getWorldTransform().getRotation().getAngle(), glm::vec3(0, 1, 0));
	mvp = glm::translate(mvp, glmCarTranslation);

	// Sun
	float scale = 0.3f;
	glm::mat4 sunMat4 = mvp;
	sunMat4 = glm::translate(sunMat4, pointLight.position);
	sunMat4 = glm::scale(sunMat4, glm::vec3(scale, scale, scale));

	// Cube Model (Air)
	airnoiseShader->use();
	airnoiseShader->setUniformFloat("time", time);
	airnoiseShader->setUniformMatrix4("modelViewProjectionMatrix", glm::translate(mvp, glm::vec3(-150.0f, -100.0f, 150.0f)));
	cube_model->draw(airnoiseShader);

	// Checkers Model
	simpleShader->use();
	simpleShader->setUniformInt("s_texture", 0);
	glUniform1i(simpleShader->getUniformLocation("s_normals"), 1);
	glBindTexture(GL_TEXTURE_2D, normals_texture->tid());
	simpleShader->setUniformMatrix4("modelViewMatrix", modelViewMatrix);
	simpleShader->setUniformVec3("light.position", pointLight.position);
	simpleShader->setUniformVec3("light.intensities", pointLight.intensities);
	simpleShader->setUniformFloat("light.attenuation", pointLight.attentuation);
	simpleShader->setUniformFloat("light.ambientCoefficient", pointLight.ambientCoefficient);
	simpleShader->setUniformFloat("time", time);
	simpleShader->setUniformVec3("materialSpecularColor", glm::vec3(1.0f, 1.0f, 1.0f));
	simpleShader->setUniformFloat("materialShininess", 5.0f);
	simpleShader->setUniformVec3("cameraPosition", extractCameraPosition(mvp));
	simpleShader->setUniformMatrix4("modelViewProjectionMatrix", mvp);
	checkers_model->draw(simpleShader);

	// Sun
	sunShader->use();
	sunShader->setUniformMatrix4("modelViewMatrix", modelViewMatrix);
	sunShader->setUniformFloat("time", time);
	sunShader->setUniformMatrix4("modelViewProjectionMatrix", sunMat4);
	sunShader->setUniformVec2("screenSize", screenSize);
	sunShader->setUniformVec3("lightPosition", pointLight.position);
	sun_model->draw(sunShader);

	// Racetrack
	noiseShader->use();
	glUniform1i(noiseShader->getUniformLocation("s_normals"), 0);
	glBindTexture(GL_TEXTURE_2D, normals_texture->tid());
	noiseShader->setUniformMatrix4("modelViewMatrix", modelViewMatrix);
	noiseShader->setUniformVec3("light.position", pointLight.position);
	noiseShader->setUniformVec3("light.intensities", pointLight.intensities);
	noiseShader->setUniformFloat("light.attenuation", pointLight.attentuation);
	noiseShader->setUniformFloat("light.ambientCoefficient", pointLight.ambientCoefficient);
	noiseShader->setUniformFloat("time", time);
	noiseShader->setUniformVec3("materialSpecularColor", glm::vec3(1.0f, 1.0f, 1.0f));
	noiseShader->setUniformVec3("cameraPosition", extractCameraPosition(mvp));
	noiseShader->setUniformFloat("materialShininess", 5.0f);
	noiseShader->setUniformMatrix4("modelViewProjectionMatrix", mvp);
	racetrack_model->draw(noiseShader);
	physics.world->debugDrawWorld();

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glViewport(0, 0, screenSize.x, screenSize.y);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	std::vector<glm::vec2> verts;
	verts.push_back(glm::vec2(-1, -1));
	verts.push_back(glm::vec2(1, -1));
	verts.push_back(glm::vec2(1, 1));
	verts.push_back(glm::vec2(-1, 1));

	//glBindBuffer(GL_ARRAY_BUFFER, 0);
	ShaderProgram* curFBOShader = fbo.fboShaders[fbo.currentShader];
	curFBOShader->use();
	curFBOShader->setUniformFloat("time", time);
	curFBOShader->setUniformVec2("screenSize", screenSize);
	curFBOShader->setUniformVec3("lightPosition", pointLight.position);
	curFBOShader->setUniformMatrix4("mvp", modelViewMatrix);
	//curFBOShader->setUniformInt("s_texture", 0);
	glBindVertexArray(0);
	glEnableVertexAttribArray(0);							// en vertex attribute 1
	glDisableVertexAttribArray(1);							// disable vertex attribute 1
	glDisableVertexAttribArray(2);							// disable vertex attribute 1
	glBindTexture(GL_TEXTURE_2D, fbo.fboTextureID);
	glVertexAttribPointer(0, 2, GL_FLOAT, false, 2 * 4, &verts[0]);									//geef aan dat de posities op deze locatie zitten
	glDrawArrays(GL_QUADS, 0, verts.size());
	glBindTexture(GL_TEXTURE_2D, 0);
	glDisableVertexAttribArray(0);
	glUseProgram(0);
}

// No Scaling
glm::vec3 App::extractCameraPosition(const glm::mat4 &modelView)
{
	glm::mat3 rotMat = glm::mat3(modelView);
	glm::vec3 d(modelView[3]);
	return -d * rotMat;
}
<commit_msg>oculus rift support<commit_after>#pragma comment(lib,"opengl32")
#define _USE_MATH_DEFINES
#include <GL\glew.h>
#include <Windows.h>
#include <CaveLib\texture.h>
#include <CaveLib\model.h>
#include "App.h"
#include <glm/gtc/type_ptr.hpp>
#include <functional>

App::App(WiiMoteWrapper* w)
{
	wiiMoteWrapper = w;
}
App::~App(void){
	glUseProgram(0);
	glDeleteTextures(1, &fbo.fboTextureID);
	glDeleteTextures(1, &fbo.rboTextureID);
	glDeleteFramebuffers(1, &fbo.fboID);
	glDeleteRenderbuffers(1, &fbo.rboID);
}

void App::init(void)
{
	screenSize = glm::vec2(Kernel::getInstance()->getWindowWidth(), Kernel::getInstance()->getWindowHeight());
	m_pDebugDrawer = new DebugDrawer();
	m_pDebugDrawer->setDebugMode(3);
	headDevice.init("MainUserHead");
	cameraDevice.init("CameraPosition");
	physics.bullet3Init();
	cube_model = CaveLib::loadModel("data/aerial-pace-vr/models/cube.obj", new ModelLoadOptions(300.0f));
	checkers_model = CaveLib::loadModel("data/aerial-pace-vr/models/checkers_sphere.obj", new ModelLoadOptions(10.0f));
	sun_model = CaveLib::loadModel("data/aerial-pace-vr/models/checkers_sphere.obj", new ModelLoadOptions(10.0f));
	racetrack_model = CaveLib::loadModel("data/aerial-pace-vr/models/racetrack.obj", new ModelLoadOptions(100.0f));
	normals_texture = CaveLib::loadTexture("data/aerial-pace-vr/textures/normalmap3a.png", new TextureLoadOptions(GL_FALSE));
	pointLight.position = glm::vec3(60.0f, 20.0f, -10.0f);
	pointLight.intensities = glm::vec3(1.0f, 1.0f, 1.0f);
	pointLight.ambientCoefficient = 0.6f;
	pointLight.attentuation = 0.2f;
	physics.addFloor(racetrack_model);

	simpleShader = new ShaderProgram("data/aerial-pace-vr/shaders/simple.vert", "data/aerial-pace-vr/shaders/simple.frag");
	simpleShader->link();

	noiseShader = new ShaderProgram("data/aerial-pace-vr/shaders/perlinnoise.vert", "data/aerial-pace-vr/shaders/perlinnoise.frag");
	noiseShader->link();

	sunShader = new ShaderProgram("data/aerial-pace-vr/shaders/sunshader.vert", "data/aerial-pace-vr/shaders/sunshader.frag");
	sunShader->link();

	airnoiseShader = new ShaderProgram("data/aerial-pace-vr/shaders/airnoise.vert", "data/aerial-pace-vr/shaders/airnoise.frag");
	airnoiseShader->link();

	std::vector<string> shaders;
	shaders.push_back("normalpostprocess");
	shaders.push_back("blur");
	//shaders.push_back("threshold");
	shaders.push_back("mirror1");
	shaders.push_back("mirror2");
	shaders.push_back("mirror3");
	//shaders.push_back("draaien");
	shaders.push_back("shining");
	//shaders.push_back("sunprocessing");

	for each (string shader in shaders)
		fbo.fboShaders.push_back(new ShaderProgram("data/aerial-pace-vr/shaders/fbo/"+shader+".vert", "data/aerial-pace-vr/shaders/fbo/"+shader+".frag"));
	for each (ShaderProgram* program in fbo.fboShaders)
	{
		program->link();
		program->setUniformInt("s_texture", 0);
	}

	physics.world->setDebugDrawer(m_pDebugDrawer);

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);

	//fbo
	GLint oldFbo;
	glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFbo);
	glGenTextures(1, &fbo.fboID);
	glBindTexture(GL_TEXTURE_2D, fbo.fboTextureID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glGenFramebuffers(1, &fbo.fboID);
	glBindFramebuffer(GL_FRAMEBUFFER, fbo.fboID);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenSize.x, screenSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.fboTextureID, 0);
	glGenRenderbuffers(1, &fbo.rboID);
	glGenTextures(1, &fbo.rboTextureID);
	glBindTexture(1, fbo.rboTextureID);
	glBindRenderbuffer(GL_RENDERBUFFER, fbo.rboID);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenSize.x, screenSize.y);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo.rboID);
	//auto b = glewGetErrorString(glGetError());
	GLenum e = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
	if (e != GL_FRAMEBUFFER_COMPLETE)
		printf("There is a problem with the FBO\n");
	glBindFramebuffer(GL_FRAMEBUFFER, oldFbo);
}

void App::preFrame(double frameTime, double totalTime)
{
	// timer
	clock_t clock_end = clock();
	GLfloat timeFctr = GLfloat(clock_end - clock_start) / CLOCKS_PER_SEC; // calculate time(s) elapsed since last frame
	fps = int(1 / timeFctr);
	clock_start = clock();
	if (GetAsyncKeyState(82) != 0){
		//physics.addCar();
	}

	if (GetAsyncKeyState(VK_RIGHT)){
		if (nextTimeToCheck < clock()){
			fbo.currentShader++;
			fbo.currentShader %= fbo.fboShaders.size();
			nextTimeToCheck = clock() + 200;
		}
	}

	if (GetAsyncKeyState(VK_LEFT)){
		if (nextTimeToCheck < clock()){
			fbo.currentShader--;
			if (fbo.currentShader == -1)
				fbo.currentShader = fbo.fboShaders.size() - 1;
			nextTimeToCheck = clock() + 200;
		}
	}

	//Check I
	if (GetAsyncKeyState(73) != 0)
	{
		wiiMoteWrapper->buttonOne = true;
	}
	else
		wiiMoteWrapper->buttonOne = false;
	//Check J
	if (GetAsyncKeyState(74) != 0)
	{
		wiiMoteWrapper->degrees = -30;
	}
	//Check K
	if (GetAsyncKeyState(75) != 0)
	{
		wiiMoteWrapper->buttonTwo = true;
	}
	else
		wiiMoteWrapper->buttonTwo = false;
	//Check L
	if (GetAsyncKeyState(76) != 0)
	{
		wiiMoteWrapper->degrees = 30;
	}
	if (GetAsyncKeyState(74) == 0 && GetAsyncKeyState(76) == 0)
		wiiMoteWrapper->degrees = 0;
	physics.updateCar(timeFctr,wiiMoteWrapper);
}

void App::draw(const glm::mat4 &projectionMatrix, const glm::mat4 &modelViewMatrix)
{
	GLint oldFbo;
	glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFbo);

	GLint viewport[4];
	glGetIntegerv(GL_VIEWPORT, viewport);
	//if (viewport[0] == viewport[2]){		viewport[2] = screenSize.x;	}
	//glBindFramebuffer(GL_FRAMEBUFFER, fbo.fboID);
 	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_COLOR_MATERIAL);

	float mvpRaw[16];
	physics.realCar->getWorldTransform().getOpenGLMatrix(mvpRaw);

	// Car
	btVector3 carTranslation = physics.realCar->getWorldTransform().getOrigin();
	glm::vec3 cameraPosition(0, 0, 10.0f);
	glm::vec3 glmCarTranslation(-carTranslation.x(), -carTranslation.y() - 2, -carTranslation.z());

	// Devices
	glm::mat4 headData = headDevice.getData();
	glm::mat4 viewMatrix = modelViewMatrix * headData;

	// Update the uniform time variable.
	GLfloat time = GLfloat(clock()) / GLfloat(CLOCKS_PER_SEC);

	// Mvp
	glm::mat4 mvp = projectionMatrix * viewMatrix; // glm::mat4 mvp = projectionMatrix * modelViewMatrix;
	mvp = glm::rotate(mvp, -physics.realCar->getWorldTransform().getRotation().getAngle(), glm::vec3(0, 1, 0));
	mvp = glm::translate(mvp, glmCarTranslation);

	// Sun
	float scale = 0.3f;
	glm::mat4 sunMat4 = mvp;
	sunMat4 = glm::translate(sunMat4, pointLight.position);
	sunMat4 = glm::scale(sunMat4, glm::vec3(scale, scale, scale));

	// Cube Model (Air)
	airnoiseShader->use();
	airnoiseShader->setUniformFloat("time", time);
	airnoiseShader->setUniformMatrix4("modelViewProjectionMatrix", glm::translate(mvp, glm::vec3(-150.0f, -100.0f, 150.0f)));
	cube_model->draw(airnoiseShader);

	// Checkers Model
	simpleShader->use();
	simpleShader->setUniformInt("s_texture", 0);
	glUniform1i(simpleShader->getUniformLocation("s_normals"), 1);
	glBindTexture(GL_TEXTURE_2D, normals_texture->tid());
	simpleShader->setUniformMatrix4("modelViewMatrix", modelViewMatrix);
	simpleShader->setUniformVec3("light.position", pointLight.position);
	simpleShader->setUniformVec3("light.intensities", pointLight.intensities);
	simpleShader->setUniformFloat("light.attenuation", pointLight.attentuation);
	simpleShader->setUniformFloat("light.ambientCoefficient", pointLight.ambientCoefficient);
	simpleShader->setUniformFloat("time", time);
	simpleShader->setUniformVec3("materialSpecularColor", glm::vec3(1.0f, 1.0f, 1.0f));
	simpleShader->setUniformFloat("materialShininess", 5.0f);
	simpleShader->setUniformVec3("cameraPosition", extractCameraPosition(mvp));
	simpleShader->setUniformMatrix4("modelViewProjectionMatrix", mvp);
	checkers_model->draw(simpleShader);

	// Sun
	sunShader->use();
	sunShader->setUniformMatrix4("modelViewMatrix", modelViewMatrix);
	sunShader->setUniformFloat("time", time);
	sunShader->setUniformMatrix4("modelViewProjectionMatrix", sunMat4);
	sunShader->setUniformVec2("screenSize", screenSize);
	sunShader->setUniformVec3("lightPosition", pointLight.position);
	sun_model->draw(sunShader);

	// Racetrack
	noiseShader->use();
	glUniform1i(noiseShader->getUniformLocation("s_normals"), 0);
	glBindTexture(GL_TEXTURE_2D, normals_texture->tid());
	noiseShader->setUniformMatrix4("modelViewMatrix", modelViewMatrix);
	noiseShader->setUniformVec3("light.position", pointLight.position);
	noiseShader->setUniformVec3("light.intensities", pointLight.intensities);
	noiseShader->setUniformFloat("light.attenuation", pointLight.attentuation);
	noiseShader->setUniformFloat("light.ambientCoefficient", pointLight.ambientCoefficient);
	noiseShader->setUniformFloat("time", time);
	noiseShader->setUniformVec3("materialSpecularColor", glm::vec3(1.0f, 1.0f, 1.0f));
	noiseShader->setUniformVec3("cameraPosition", extractCameraPosition(mvp));
	noiseShader->setUniformFloat("materialShininess", 5.0f);
	noiseShader->setUniformMatrix4("modelViewProjectionMatrix", mvp);
	racetrack_model->draw(noiseShader);
	physics.world->debugDrawWorld();

	//glBindFramebuffer(GL_FRAMEBUFFER, oldFbo);
	//glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//std::vector<glm::vec2> verts;
	//verts.push_back(glm::vec2(-1, -1));
	//verts.push_back(glm::vec2(1, -1));
	//verts.push_back(glm::vec2(1, 1));
	//verts.push_back(glm::vec2(-1, 1));

	////glBindBuffer(GL_ARRAY_BUFFER, 0);
	//ShaderProgram* curFBOShader = fbo.fboShaders[fbo.currentShader];
	//curFBOShader->use();
	//curFBOShader->setUniformFloat("time", time);
	//curFBOShader->setUniformVec2("screenSize", screenSize);
	//curFBOShader->setUniformVec3("lightPosition", pointLight.position);
	////curFBOShader->setUniformInt("s_texture", 0);
	//glBindVertexArray(0);
	//glEnableVertexAttribArray(0);                                                   // en vertex attribute 1
	//glDisableVertexAttribArray(1);                                                  // disable vertex attribute 1
	//glDisableVertexAttribArray(2);                                                  // disable vertex attribute 1
	//glBindTexture(GL_TEXTURE_2D, fbo.fboTextureID);
	//glVertexAttribPointer(0, 2, GL_FLOAT, false, 2 * 4, &verts[0]);                                                                 //geef aan dat de posities op deze locatie zitten
	//glDrawArrays(GL_QUADS, 0, verts.size());
	//glBindTexture(GL_TEXTURE_2D, 0);
	//glDisableVertexAttribArray(0);
	glUseProgram(0);
}

// No Scaling
glm::vec3 App::extractCameraPosition(const glm::mat4 &modelView)
{
	glm::mat3 rotMat = glm::mat3(modelView);
	glm::vec3 d(modelView[3]);
	return -d * rotMat;
}
<|endoftext|>


<commit_before>/*
*	Car.cpp
*/
#include "Smartcar.h"
/* --- CAR --- */

const unsigned short Car::DEFAULT_PID_LOOP_INTERVAL = 80;
const unsigned short Car::STANDARD = 1;
const unsigned short Car::INVERTED = 0;
const float Car::DEFAULT_KP = 5.0;
const float Car::DEFAULT_KI = 0.0;
const float Car::DEFAULT_KD = 10.0;

const unsigned short BACKWARD = 0;
const unsigned short FORWARD = 1;
const unsigned short IDLE = 2;

const int IDLE_RAW_SPEED = 0;
const int MAX_FRONT_RAW_SPEED = 255;
const int MAX_BACK_RAW_SPEED = -255;
const float MAX_BACK_CRUISE_SPEED = -3.0;
const float MAX_FRONT_CRUISE_SPEED = 3.0;
const int STRAIGHT_WHEELS = 90;
const int STRAIGHT_ANGLE = 0;
const int MAX_RIGHT_DEGREES = 180;
const int MAX_LEFT_DEGREES = 0;
const float GO_CRUISE_SPEED = 1.3;
const int GO_RAW_SPEED = 200;
const int MAX_RIGHT_STEERING_ANGLE = MAX_RIGHT_DEGREES - STRAIGHT_WHEELS;
const int MAX_LEFT_STEERING_ANGLE = MAX_LEFT_DEGREES - STRAIGHT_WHEELS;

Car::Car(const unsigned short setup){
	_cruiseControl = false;
	_speed = IDLE_RAW_SPEED;
	_angle = STRAIGHT_WHEELS;
	_numOfEncoders = 0;
	if (setup == STANDARD){ //the default motor setup, where right is right
		MOTOR_LEFT1_PIN = 8;
		MOTOR_LEFT_EN_PIN = 9;
		MOTOR_LEFT2_PIN = 10;
		MOTOR_RIGHT_EN_PIN = 11;
		MOTOR_RIGHT1_PIN = 12;
		MOTOR_RIGHT2_PIN = 13;
	}else{ //the reversed motor setup, where right is left
		MOTOR_RIGHT1_PIN = 8;
		MOTOR_RIGHT_EN_PIN = 9;
		MOTOR_RIGHT2_PIN = 10;
		MOTOR_LEFT_EN_PIN = 11;
		MOTOR_LEFT1_PIN = 12;
		MOTOR_LEFT2_PIN = 13;
	}
}

void Car::begin(){
	for (uint8_t i = MOTOR_LEFT1_PIN; i <= MOTOR_RIGHT2_PIN; i++) {
		pinMode(i, OUTPUT); //declare pins as outputs
	}
	setSpeed(IDLE_RAW_SPEED);
	setAngle(STRAIGHT_ANGLE);
}

void Car::begin(Odometer encoder){
	_encoders[0] = encoder;
	_numOfEncoders = 1;
	begin();
}

void Car::begin(Gyroscope gyro){
	_gyro = gyro;
	begin();
}

void Car::begin(Odometer encoder, Gyroscope gyro){
	_encoders[0] = encoder;
	_numOfEncoders = 1;
	_gyro = gyro;
	begin();
}

void Car::begin(Odometer encoder1, Odometer encoder2){
	_encoders[0] = encoder1;
	_encoders[1] = encoder2;
	_numOfEncoders = 2;
	begin();
}

void Car::begin(Odometer encoder1, Odometer encoder2, Gyroscope gyro){
	_encoders[0] = encoder1;
	_encoders[1] = encoder2;
	_numOfEncoders = 2;
	_gyro = gyro;
	begin();
}

void Car::setSpeed(float newSpeed){
	if (cruiseControlEnabled()){
		if (_speed && (_speed != IDLE_RAW_SPEED) && (newSpeed * _speed) <= 0) stop(); //if the speeds are signed differently, stop the car and then set the new speed. Ignore this if the speed is already 0 and if speed is at the idle raw speed i.e. leftovers from non-cruise control mode (if IDLE_RAW_SPEED is not 0, it makes sense)
		_speed = constrain(newSpeed, MAX_BACK_CRUISE_SPEED, MAX_FRONT_CRUISE_SPEED);
	}else{
		_speed = constrain(int(newSpeed), MAX_BACK_RAW_SPEED, MAX_FRONT_RAW_SPEED);
		setMotors(_speed, getAngle());
	}
}

void Car::updateMotors(){
	if (cruiseControlEnabled() && (millis() > _lastMotorUpdate + _pidLoopInterval)){
		if (_speed){ //if _speed is 0, we have already made sure the car is stopped. don't try to adjust if car is just drifting
			float measuredSpeed = getGroundSpeed(); //speed in cm/milliseconds
			measuredSpeed *= 10; //transform it into m/seconds, divide by 100 to turn cm into m and multiply by 1000, to turn ms to sec
			if (_speed < 0) measuredSpeed *= -1; //if we are going reverse, illustrate that in the value of measuredSpeed
			int controlledSpeed = motorPIDcontrol(_previousControlledSpeed, _speed, measuredSpeed);
			setMotors(controlledSpeed, getAngle());
			_previousControlledSpeed = controlledSpeed;
		}
		_lastMotorUpdate = millis();
	}
}

int Car::motorPIDcontrol(const int previousSpeed, const float targetSpeed, const float actualSpeed){
	float correction = 0;
	float error = targetSpeed - actualSpeed;
	_integratedError += error;
	correction = (_Kp * error) + (_Ki * _integratedError) + (_Kd * (error - _previousError));
	_previousError = error;
	return constrain(previousSpeed + int(correction), MAX_BACK_RAW_SPEED, MAX_FRONT_RAW_SPEED);
}

float Car::getGroundSpeed(){
	unsigned long currentDistance = getEncoderDistance();
	unsigned long dX = currentDistance - _previousDistance;
	_previousDistance = currentDistance;
	unsigned long dT = millis() - _lastMotorUpdate;
	float velocity = float(dX)/ float(dT);
	return velocity;
}

void Car::setMotors(int rawSpeed, int angle){ //platform specific method
	if (rawSpeed < 0){
		setDirection(BACKWARD);
	}else if (rawSpeed > 0){
		setDirection(FORWARD);
	}else{
		setDirection(IDLE);
	}
	rawSpeed = abs(rawSpeed);
	float ratio = (STRAIGHT_WHEELS - abs(angle));
	ratio /= STRAIGHT_WHEELS;
	if (angle>0){ //going to the right
		analogWrite(MOTOR_LEFT_EN_PIN, rawSpeed);
		analogWrite(MOTOR_RIGHT_EN_PIN, int(rawSpeed * ratio));
	}else{ //going to the left or straight
		analogWrite(MOTOR_RIGHT_EN_PIN, rawSpeed);
		analogWrite(MOTOR_LEFT_EN_PIN, int(rawSpeed * ratio));
	}

}

void Car::setDirection(const unsigned short direction){ //platform specific method
	if (direction == BACKWARD){
		digitalWrite(MOTOR_RIGHT1_PIN, LOW);
		digitalWrite(MOTOR_RIGHT2_PIN, HIGH);
		digitalWrite(MOTOR_LEFT1_PIN, LOW);
		digitalWrite(MOTOR_LEFT2_PIN, HIGH);
	}else if (direction == FORWARD){
		digitalWrite(MOTOR_RIGHT1_PIN, HIGH);
		digitalWrite(MOTOR_RIGHT2_PIN, LOW);
		digitalWrite(MOTOR_LEFT1_PIN, HIGH);
		digitalWrite(MOTOR_LEFT2_PIN, LOW);
	}else{
		digitalWrite(MOTOR_RIGHT1_PIN, LOW);
		digitalWrite(MOTOR_RIGHT2_PIN, LOW);
		digitalWrite(MOTOR_LEFT1_PIN, LOW);
		digitalWrite(MOTOR_LEFT2_PIN, LOW);
	}
}

void Car::setAngle(int angle){ //platform specific method
	_angle = constrain(angle, MAX_LEFT_DEGREES - STRAIGHT_WHEELS, MAX_RIGHT_DEGREES - STRAIGHT_WHEELS); //constrain the value to the permitted valued the user is allowed to supply
	setMotors(getSpeed(), getAngle()); //pass the human-readable value that was just supplied
}

void Car::stop(){ //platform specific method
	if (getSpeed()>0){
		setMotors(-100, getAngle());
	}else if(getSpeed()<0){
		setMotors(100, getAngle());
	}
	delay(80); //go the opposite direction for a few milliseconds, to make sure we are stopped
	if (cruiseControlEnabled()){
		setMotors(0,getAngle()); //shut the engines down, we should be stopped by now
		enableCruiseControl(_Kp,_Ki,_Kd); //re-initialize the cruise control, se we get rid of previous error and pid output
		_speed = 0.0;
	}else{
		setSpeed(0); //no circular dependency between stop and setSpeed due to the cruiseControlEnabled switching between who uses what
	}
}

float Car::getSpeed(){
	if (cruiseControlEnabled()) return getGroundSpeed(); //return speed in meters per second
	return _speed; //return speed in PWM output
}

int Car::getAngle(){
	return _angle; //return what the user supplied
}

void Car::enableCruiseControl(float Kp, float Ki, float Kd, unsigned short pidLoopInterval){
	_cruiseControl = true;
	_pidLoopInterval = pidLoopInterval;
	_lastMotorUpdate = 0;
	_previousControlledSpeed = IDLE_RAW_SPEED;
	_previousDistance = getEncoderDistance();
	_integratedError = 0;
	_Kp = Kp;
	_Ki = Ki;
	_Kd = Kd;
}

void Car::disableCruiseControl(){
	_cruiseControl = false;
	_speed = _previousControlledSpeed; //update the speed with the PWM equivalent
}

boolean Car::cruiseControlEnabled(){
	return _cruiseControl;
}

unsigned long Car::getEncoderDistance(){
	unsigned long averageDistance = 0;
	for (int i = 0; i < _numOfEncoders; i++){
		averageDistance += _encoders[i].getDistance() / _numOfEncoders;
	}
	return averageDistance;
}

void Car::initializeEncoders(){
	for (int i = 0; i < _numOfEncoders; i++){
		_encoders[i].begin();
	}
}

void Car::go(int centimeters){
	unsigned long initialDistance = getEncoderDistance(); //save the current distance the car has covered
	float initialSpeed = getSpeed(); //save the current speed (so we restore it later)
	int initialAngle = getAngle(); //save the current angle (so we restore it later)
	unsigned long targetDistance = initialDistance + abs(centimeters); //how much the car should move, always a positive number
	if (initialDistance > targetDistance){ //this will occur only if the unsigned long variable overflows
		initializeEncoders(); //reinitialize the encoders counter to 0
		targetDistance = abs(centimeters); //now the new target is just the centimeters (since the encoder distance is 0)
	}
	setAngle(STRAIGHT_ANGLE); //set the angle straight
	short direction = 1;
	if (centimeters < 0) direction = -1; //if the user supplied a negative argument, means they want to move backwards
	if (cruiseControlEnabled()){ //depending on whether the cruise control is enabled set the speed
		setSpeed(direction * GO_CRUISE_SPEED);
	}else{
		setSpeed(direction * GO_RAW_SPEED);
	}
	while (getEncoderDistance() < targetDistance){ //while we haven't reached the target distance, keep moving
		if (cruiseControlEnabled()) updateMotors(); //otherwise the pid for the motors won't work
	}
	setSpeed(initialSpeed); //restore to the initial speed
	setAngle(initialAngle); //restore to the inital angle
}
void Car::rotate(int targetDegrees){
	_gyro.begin(); //initialize the gyro
	float initialSpeed = getSpeed(); //save the current speed (so we restore it later)
	int initialAngle = getAngle(); //save the current angle (so we restore it later)
	if (targetDegrees > 0){ //we should turn to the right (clockwise)
		setAngle(MAX_RIGHT_STEERING_ANGLE); //turn right as steep as you can
	}else{ //turn left (counterclockwise)
		setAngle(MAX_LEFT_STEERING_ANGLE); //turn left as steep as you can
	}
	if (cruiseControlEnabled()){ //depending on whether the cruise control is enabled set the speed
		setSpeed(GO_CRUISE_SPEED);
	}else{
		setSpeed(GO_RAW_SPEED);
	}
	while (abs(_gyro.getAngularDisplacement()) < abs(targetDegrees)){ //while the absolute displacement hasn't reached the (absolute) target, keep turning
		if (cruiseControlEnabled()) updateMotors(); //otherwise the pid for the motors won't work
		_gyro.update(); //update to integrate the latest gyroscope readings
	}
	setSpeed(initialSpeed); //restore to the initial speed
	setAngle(initialAngle); //restore to the inital angle
}

void Car::setMotorSpeed(int leftMotorSpeed, int rightMotorSpeed){ //will set the speed manual to each motor, use with caution
	if (cruiseControlEnabled()) return; //we don't want to be manually messing with the speed, during cruise control
	leftMotorSpeed = constrain(leftMotorSpeed, MAX_BACK_RAW_SPEED, MAX_FRONT_RAW_SPEED); //constrain the speed within the allowed limits
	rightMotorSpeed = constrain(rightMotorSpeed, MAX_BACK_RAW_SPEED, MAX_FRONT_RAW_SPEED);
	if (leftMotorSpeed<0){ //set left direction backwards
		digitalWrite(MOTOR_LEFT1_PIN, LOW);
		digitalWrite(MOTOR_LEFT2_PIN, HIGH);
	}else{ //front
		digitalWrite(MOTOR_LEFT1_PIN, HIGH);
		digitalWrite(MOTOR_LEFT2_PIN, LOW);
	}
		analogWrite(MOTOR_LEFT_EN_PIN, abs(leftMotorSpeed));//write left speed
	if (rightMotorSpeed<0){ //set right direction  backwards
		digitalWrite(MOTOR_RIGHT1_PIN, LOW);
		digitalWrite(MOTOR_RIGHT2_PIN, HIGH);
	}else{ //front
		digitalWrite(MOTOR_RIGHT1_PIN, HIGH);
		digitalWrite(MOTOR_RIGHT2_PIN, LOW);
	}
		analogWrite(MOTOR_RIGHT_EN_PIN, abs(rightMotorSpeed));//write right speed
}
<commit_msg>go works only if encoders were attached)<commit_after>/*
*	Car.cpp
*/
#include "Smartcar.h"
/* --- CAR --- */

const unsigned short Car::DEFAULT_PID_LOOP_INTERVAL = 80;
const unsigned short Car::STANDARD = 1;
const unsigned short Car::INVERTED = 0;
const float Car::DEFAULT_KP = 5.0;
const float Car::DEFAULT_KI = 0.0;
const float Car::DEFAULT_KD = 10.0;

const unsigned short BACKWARD = 0;
const unsigned short FORWARD = 1;
const unsigned short IDLE = 2;

const int IDLE_RAW_SPEED = 0;
const int MAX_FRONT_RAW_SPEED = 255;
const int MAX_BACK_RAW_SPEED = -255;
const float MAX_BACK_CRUISE_SPEED = -3.0;
const float MAX_FRONT_CRUISE_SPEED = 3.0;
const int STRAIGHT_WHEELS = 90;
const int STRAIGHT_ANGLE = 0;
const int MAX_RIGHT_DEGREES = 180;
const int MAX_LEFT_DEGREES = 0;
const float GO_CRUISE_SPEED = 1.3;
const int GO_RAW_SPEED = 200;
const int MAX_RIGHT_STEERING_ANGLE = MAX_RIGHT_DEGREES - STRAIGHT_WHEELS;
const int MAX_LEFT_STEERING_ANGLE = MAX_LEFT_DEGREES - STRAIGHT_WHEELS;

Car::Car(const unsigned short setup){
	_cruiseControl = false;
	_speed = IDLE_RAW_SPEED;
	_angle = STRAIGHT_WHEELS;
	_numOfEncoders = 0;
	if (setup == STANDARD){ //the default motor setup, where right is right
		MOTOR_LEFT1_PIN = 8;
		MOTOR_LEFT_EN_PIN = 9;
		MOTOR_LEFT2_PIN = 10;
		MOTOR_RIGHT_EN_PIN = 11;
		MOTOR_RIGHT1_PIN = 12;
		MOTOR_RIGHT2_PIN = 13;
	}else{ //the reversed motor setup, where right is left
		MOTOR_RIGHT1_PIN = 8;
		MOTOR_RIGHT_EN_PIN = 9;
		MOTOR_RIGHT2_PIN = 10;
		MOTOR_LEFT_EN_PIN = 11;
		MOTOR_LEFT1_PIN = 12;
		MOTOR_LEFT2_PIN = 13;
	}
}

void Car::begin(){
	for (uint8_t i = MOTOR_LEFT1_PIN; i <= MOTOR_RIGHT2_PIN; i++) {
		pinMode(i, OUTPUT); //declare pins as outputs
	}
	setSpeed(IDLE_RAW_SPEED);
	setAngle(STRAIGHT_ANGLE);
}

void Car::begin(Odometer encoder){
	_encoders[0] = encoder;
	_numOfEncoders = 1;
	begin();
}

void Car::begin(Gyroscope gyro){
	_gyro = gyro;
	begin();
}

void Car::begin(Odometer encoder, Gyroscope gyro){
	_encoders[0] = encoder;
	_numOfEncoders = 1;
	_gyro = gyro;
	begin();
}

void Car::begin(Odometer encoder1, Odometer encoder2){
	_encoders[0] = encoder1;
	_encoders[1] = encoder2;
	_numOfEncoders = 2;
	begin();
}

void Car::begin(Odometer encoder1, Odometer encoder2, Gyroscope gyro){
	_encoders[0] = encoder1;
	_encoders[1] = encoder2;
	_numOfEncoders = 2;
	_gyro = gyro;
	begin();
}

void Car::setSpeed(float newSpeed){
	if (cruiseControlEnabled()){
		if (_speed && (_speed != IDLE_RAW_SPEED) && (newSpeed * _speed) <= 0) stop(); //if the speeds are signed differently, stop the car and then set the new speed. Ignore this if the speed is already 0 and if speed is at the idle raw speed i.e. leftovers from non-cruise control mode (if IDLE_RAW_SPEED is not 0, it makes sense)
		_speed = constrain(newSpeed, MAX_BACK_CRUISE_SPEED, MAX_FRONT_CRUISE_SPEED);
	}else{
		_speed = constrain(int(newSpeed), MAX_BACK_RAW_SPEED, MAX_FRONT_RAW_SPEED);
		setMotors(_speed, getAngle());
	}
}

void Car::updateMotors(){
	if (cruiseControlEnabled() && (millis() > _lastMotorUpdate + _pidLoopInterval)){
		if (_speed){ //if _speed is 0, we have already made sure the car is stopped. don't try to adjust if car is just drifting
			float measuredSpeed = getGroundSpeed(); //speed in cm/milliseconds
			measuredSpeed *= 10; //transform it into m/seconds, divide by 100 to turn cm into m and multiply by 1000, to turn ms to sec
			if (_speed < 0) measuredSpeed *= -1; //if we are going reverse, illustrate that in the value of measuredSpeed
			int controlledSpeed = motorPIDcontrol(_previousControlledSpeed, _speed, measuredSpeed);
			setMotors(controlledSpeed, getAngle());
			_previousControlledSpeed = controlledSpeed;
		}
		_lastMotorUpdate = millis();
	}
}

int Car::motorPIDcontrol(const int previousSpeed, const float targetSpeed, const float actualSpeed){
	float correction = 0;
	float error = targetSpeed - actualSpeed;
	_integratedError += error;
	correction = (_Kp * error) + (_Ki * _integratedError) + (_Kd * (error - _previousError));
	_previousError = error;
	return constrain(previousSpeed + int(correction), MAX_BACK_RAW_SPEED, MAX_FRONT_RAW_SPEED);
}

float Car::getGroundSpeed(){
	unsigned long currentDistance = getEncoderDistance();
	unsigned long dX = currentDistance - _previousDistance;
	_previousDistance = currentDistance;
	unsigned long dT = millis() - _lastMotorUpdate;
	float velocity = float(dX)/ float(dT);
	return velocity;
}

void Car::setMotors(int rawSpeed, int angle){ //platform specific method
	if (rawSpeed < 0){
		setDirection(BACKWARD);
	}else if (rawSpeed > 0){
		setDirection(FORWARD);
	}else{
		setDirection(IDLE);
	}
	rawSpeed = abs(rawSpeed);
	float ratio = (STRAIGHT_WHEELS - abs(angle));
	ratio /= STRAIGHT_WHEELS;
	if (angle>0){ //going to the right
		analogWrite(MOTOR_LEFT_EN_PIN, rawSpeed);
		analogWrite(MOTOR_RIGHT_EN_PIN, int(rawSpeed * ratio));
	}else{ //going to the left or straight
		analogWrite(MOTOR_RIGHT_EN_PIN, rawSpeed);
		analogWrite(MOTOR_LEFT_EN_PIN, int(rawSpeed * ratio));
	}

}

void Car::setDirection(const unsigned short direction){ //platform specific method
	if (direction == BACKWARD){
		digitalWrite(MOTOR_RIGHT1_PIN, LOW);
		digitalWrite(MOTOR_RIGHT2_PIN, HIGH);
		digitalWrite(MOTOR_LEFT1_PIN, LOW);
		digitalWrite(MOTOR_LEFT2_PIN, HIGH);
	}else if (direction == FORWARD){
		digitalWrite(MOTOR_RIGHT1_PIN, HIGH);
		digitalWrite(MOTOR_RIGHT2_PIN, LOW);
		digitalWrite(MOTOR_LEFT1_PIN, HIGH);
		digitalWrite(MOTOR_LEFT2_PIN, LOW);
	}else{
		digitalWrite(MOTOR_RIGHT1_PIN, LOW);
		digitalWrite(MOTOR_RIGHT2_PIN, LOW);
		digitalWrite(MOTOR_LEFT1_PIN, LOW);
		digitalWrite(MOTOR_LEFT2_PIN, LOW);
	}
}

void Car::setAngle(int angle){ //platform specific method
	_angle = constrain(angle, MAX_LEFT_DEGREES - STRAIGHT_WHEELS, MAX_RIGHT_DEGREES - STRAIGHT_WHEELS); //constrain the value to the permitted valued the user is allowed to supply
	setMotors(getSpeed(), getAngle()); //pass the human-readable value that was just supplied
}

void Car::stop(){ //platform specific method
	if (getSpeed()>0){
		setMotors(-100, getAngle());
	}else if(getSpeed()<0){
		setMotors(100, getAngle());
	}
	delay(80); //go the opposite direction for a few milliseconds, to make sure we are stopped
	if (cruiseControlEnabled()){
		setMotors(0,getAngle()); //shut the engines down, we should be stopped by now
		enableCruiseControl(_Kp,_Ki,_Kd); //re-initialize the cruise control, se we get rid of previous error and pid output
		_speed = 0.0;
	}else{
		setSpeed(0); //no circular dependency between stop and setSpeed due to the cruiseControlEnabled switching between who uses what
	}
}

float Car::getSpeed(){
	if (cruiseControlEnabled()) return getGroundSpeed(); //return speed in meters per second
	return _speed; //return speed in PWM output
}

int Car::getAngle(){
	return _angle; //return what the user supplied
}

void Car::enableCruiseControl(float Kp, float Ki, float Kd, unsigned short pidLoopInterval){
	_cruiseControl = true;
	_pidLoopInterval = pidLoopInterval;
	_lastMotorUpdate = 0;
	_previousControlledSpeed = IDLE_RAW_SPEED;
	_previousDistance = getEncoderDistance();
	_integratedError = 0;
	_Kp = Kp;
	_Ki = Ki;
	_Kd = Kd;
}

void Car::disableCruiseControl(){
	_cruiseControl = false;
	_speed = _previousControlledSpeed; //update the speed with the PWM equivalent
}

boolean Car::cruiseControlEnabled(){
	return _cruiseControl;
}

unsigned long Car::getEncoderDistance(){
	unsigned long averageDistance = 0;
	for (int i = 0; i < _numOfEncoders; i++){
		averageDistance += _encoders[i].getDistance() / _numOfEncoders;
	}
	return averageDistance;
}

void Car::initializeEncoders(){
	for (int i = 0; i < _numOfEncoders; i++){
		_encoders[i].begin();
	}
}

void Car::go(int centimeters){
	if (_numOfEncoders){ //do this, only if encoders were attached
		unsigned long initialDistance = getEncoderDistance(); //save the current distance the car has covered
		float initialSpeed = getSpeed(); //save the current speed (so we restore it later)
		int initialAngle = getAngle(); //save the current angle (so we restore it later)
		unsigned long targetDistance = initialDistance + abs(centimeters); //how much the car should move, always a positive number
		if (initialDistance > targetDistance){ //this will occur only if the unsigned long variable overflows
			initializeEncoders(); //reinitialize the encoders counter to 0
			targetDistance = abs(centimeters); //now the new target is just the centimeters (since the encoder distance is 0)
		}
		setAngle(STRAIGHT_ANGLE); //set the angle straight
		short direction = 1;
		if (centimeters < 0) direction = -1; //if the user supplied a negative argument, means they want to move backwards
		if (cruiseControlEnabled()){ //depending on whether the cruise control is enabled set the speed
			setSpeed(direction * GO_CRUISE_SPEED);
		}else{
			setSpeed(direction * GO_RAW_SPEED);
		}
		while (getEncoderDistance() < targetDistance){ //while we haven't reached the target distance, keep moving
			if (cruiseControlEnabled()) updateMotors(); //otherwise the pid for the motors won't work
		}
		setSpeed(initialSpeed); //restore to the initial speed
		setAngle(initialAngle); //restore to the inital angle
	}
}
void Car::rotate(int targetDegrees){
	_gyro.begin(); //initialize the gyro
	float initialSpeed = getSpeed(); //save the current speed (so we restore it later)
	int initialAngle = getAngle(); //save the current angle (so we restore it later)
	if (targetDegrees > 0){ //we should turn to the right (clockwise)
		setAngle(MAX_RIGHT_STEERING_ANGLE); //turn right as steep as you can
	}else{ //turn left (counterclockwise)
		setAngle(MAX_LEFT_STEERING_ANGLE); //turn left as steep as you can
	}
	if (cruiseControlEnabled()){ //depending on whether the cruise control is enabled set the speed
		setSpeed(GO_CRUISE_SPEED);
	}else{
		setSpeed(GO_RAW_SPEED);
	}
	while (abs(_gyro.getAngularDisplacement()) < abs(targetDegrees)){ //while the absolute displacement hasn't reached the (absolute) target, keep turning
		if (cruiseControlEnabled()) updateMotors(); //otherwise the pid for the motors won't work
		_gyro.update(); //update to integrate the latest gyroscope readings
	}
	setSpeed(initialSpeed); //restore to the initial speed
	setAngle(initialAngle); //restore to the inital angle
}

void Car::setMotorSpeed(int leftMotorSpeed, int rightMotorSpeed){ //will set the speed manual to each motor, use with caution
	if (cruiseControlEnabled()) return; //we don't want to be manually messing with the speed, during cruise control
	leftMotorSpeed = constrain(leftMotorSpeed, MAX_BACK_RAW_SPEED, MAX_FRONT_RAW_SPEED); //constrain the speed within the allowed limits
	rightMotorSpeed = constrain(rightMotorSpeed, MAX_BACK_RAW_SPEED, MAX_FRONT_RAW_SPEED);
	if (leftMotorSpeed<0){ //set left direction backwards
		digitalWrite(MOTOR_LEFT1_PIN, LOW);
		digitalWrite(MOTOR_LEFT2_PIN, HIGH);
	}else{ //front
		digitalWrite(MOTOR_LEFT1_PIN, HIGH);
		digitalWrite(MOTOR_LEFT2_PIN, LOW);
	}
		analogWrite(MOTOR_LEFT_EN_PIN, abs(leftMotorSpeed));//write left speed
	if (rightMotorSpeed<0){ //set right direction  backwards
		digitalWrite(MOTOR_RIGHT1_PIN, LOW);
		digitalWrite(MOTOR_RIGHT2_PIN, HIGH);
	}else{ //front
		digitalWrite(MOTOR_RIGHT1_PIN, HIGH);
		digitalWrite(MOTOR_RIGHT2_PIN, LOW);
	}
		analogWrite(MOTOR_RIGHT_EN_PIN, abs(rightMotorSpeed));//write right speed
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>

void trim_out_of_range(void);
int shift_right(const int idx, const int sum = 0);
int shift_down(const int idx, const int sum = 0);

int *list;
int size;
int sum;

int main(void)
{
    printf("Enter n= "); scanf("%d", &size);

    list = (int *)malloc(sizeof(int) * size);
    for(int i = 0; i < size; i++)
    {
        printf("Enter list[%d]= ", i); scanf("%d", &list[i]);
    }

    printf("Enter k= "); scanf("%d", &sum);

    trim_out_of_range();
    printf("Result: %d\n", shift_right(size - 1));

    free(list);

    return 0;
}

void trim_out_of_range(void)
{
    for(int i = size - 1; i >= 0; i--)
        if(list[i] > sum)
        {
            for(int j = i; j < size; j++) list[j] = list[j + 1];
            size--;
        }
}

int shift_right(const int idx, const int sum)
{
    if(idx < 0 && sum == ::sum) return 1;
    if(idx < 0) return 0;

    return shift_right(idx - 1, sum + list[idx]) + shift_down(idx, sum);
}

int shift_down(const int idx, const int sum)
{
    if(idx - 1 < 0) return 0;
    return shift_right(idx - 1, sum);
}
<commit_msg>Fix the error which is printing invalid result<commit_after>#include <stdio.h>
#include <stdlib.h>

void trim_out_of_range(void);
int shift_right(const int idx, const int sum = 0);
int shift_down(const int idx, const int sum = 0);

int *list;
int size;
int sum;

int main(void)
{
    printf("Enter n= "); scanf("%d", &size);

    list = (int *)malloc(sizeof(int) * size);
    for(int i = 0; i < size; i++)
    {
        printf("Enter list[%d]= ", i); scanf("%d", &list[i]);
    }

    printf("Enter k= "); scanf("%d", &sum);

    trim_out_of_range();
    printf("Result: %d\n", shift_right(size - 1));

    free(list);

    return 0;
}

void trim_out_of_range(void)
{
    for(int i = size - 1; i >= 0; i--)
        if(list[i] > sum)
        {
            for(int j = i; j < size; j++) list[j] = list[j + 1];
            size--;
        }
}

int shift_right(const int idx, const int sum)
{
    if(idx < 0 && sum == ::sum) return 1;
    if(idx < 0) return 0;

    return shift_right(idx - 1, sum + list[idx]) + shift_down(idx, sum);
}

int shift_down(const int idx, const int sum)
{
    if(idx - 1 < 0 && sum == ::sum) return 1;
    if(idx - 1 < 0) return 0;

    return shift_right(idx - 1, sum);
}
<|endoftext|>


<commit_before>/**
 * @file binary_space_tree.hpp
 * @author Ryan Curtin
 *
 * Include all the necessary files to use the BinarySpaceTree class.
 */
#ifndef __MLPACK_CORE_TREE_BINARY_SPACE_TREE_HPP
#define __MLPACK_CORE_TREE_BINARY_SPACE_TREE_HPP

#include "bounds.hpp"
#include "binary_space_tree/binary_space_tree.hpp"
#include "binary_space_tree/single_tree_traverser.hpp"
#include "binary_space_tree/single_tree_traverser_impl.hpp"
#include "binary_space_tree/dual_tree_traverser.hpp"
#include "binary_space_tree/dual_tree_traverser_impl.hpp"
#include "binary_space_tree/traits.hpp"

#endif
<commit_msg>Here's the file I forgot -- include the BreadthFirstDualTreeTraverser class definition.<commit_after>/**
 * @file binary_space_tree.hpp
 * @author Ryan Curtin
 *
 * Include all the necessary files to use the BinarySpaceTree class.
 */
#ifndef __MLPACK_CORE_TREE_BINARY_SPACE_TREE_HPP
#define __MLPACK_CORE_TREE_BINARY_SPACE_TREE_HPP

#include "bounds.hpp"
#include "binary_space_tree/binary_space_tree.hpp"
#include "binary_space_tree/single_tree_traverser.hpp"
#include "binary_space_tree/single_tree_traverser_impl.hpp"
#include "binary_space_tree/dual_tree_traverser.hpp"
#include "binary_space_tree/dual_tree_traverser_impl.hpp"
#include "binary_space_tree/breadth_first_dual_tree_traverser.hpp"
#include "binary_space_tree/breadth_first_dual_tree_traverser_impl.hpp"
#include "binary_space_tree/traits.hpp"

#endif
<|endoftext|>


<commit_before>/**
 * @file trainer.hpp
 * @author Marcus Edel
 *
 * Definition and implementation of a trainer that trains the parameters of a
 * neural network according to a supervised dataset.
 */
#ifndef __MLPACK_METHODS_ANN_TRAINER_TRAINER_HPP
#define __MLPACK_METHODS_ANN_TRAINER_TRAINER_HPP

#include <mlpack/core.hpp>

#include <mlpack/methods/ann/network_traits.hpp>
#include <mlpack/methods/ann/layer/layer_traits.hpp>

namespace mlpack {
namespace ann /** Artificial Neural Network. */ {

/**
 * Trainer that trains the parameters of a neural network according to a
 * supervised dataset.
 *
 * @tparam NetworkType The type of network which should be trained and
 * evaluated.
 * @tparam MaType Type of the error type (arma::mat or arma::sp_mat).
 */
template<
  typename NetworkType,
  typename MatType = arma::mat
>
class Trainer
{
  public:
    /**
     * Construct the Trainer object, which will be used to train a neural
     * network according to a supervised dataset by backpropagating the errors.
     *
     * If batchSize is greater 1 the trainer will take a mean gradient step over
     * this many samples and will update the parameters only at the end of
     * each epoch (Default 1).
     *
     * @param net The network that should be trained.
     * @param maxEpochs The number of maximal trained iterations (0 means no
     * limit).
     * @param batchSize The batch size used to train the network.
     * @param tolerance Train the network until it converges against
     * the specified threshold.
     * @param shuffle If true, the order of the training set is shuffled;
     * otherwise, each data is visited in linear order.
     */
    Trainer(NetworkType& net,
            const size_t maxEpochs = 0,
            const size_t batchSize = 1,
            const double tolerance = 0.0001,
            const bool shuffle = true) :
        net(net),
        maxEpochs(maxEpochs),
        batchSize(batchSize),
        tolerance(tolerance),
        shuffle(shuffle)
    {
      // Nothing to do here.
    }

    /**
     * Train the network on the given datasets until the network converges. If
     * maxEpochs is greater than zero that many epochs are maximal trained.
     *
     * @param trainingData Data used to train the network.
     * @param trainingLabels Labels used to train the network.
     * @param validationData Data used to evaluate the network.
     * @tparam validationLabels Labels used to evaluate the network.
     */
    template<typename InputType, typename OutputType>
    void Train(InputType& trainingData,
               OutputType& trainingLabels,
               InputType& validationData,
               OutputType& validationLabels)
    {
      // This generates [0 1 2 3 ... (ElementCount(trainingData) - 1)]. The
      // sequence will be used to iterate through the training data.
      index = arma::linspace<arma::Col<size_t> >(0,
          ElementCount(trainingData) - 1, ElementCount(trainingData));
      epoch = 0;

      while(true)
      {
        if (shuffle)
          index = arma::shuffle(index);

        Train<InputType, OutputType, NetworkType>(
            trainingData, trainingLabels);
        Evaluate<InputType, OutputType, NetworkType>(
            validationData, validationLabels);

        if (validationError <= tolerance)
          break;

        if (maxEpochs > 0 && ++epoch >= maxEpochs)
          break;
      }
    }

    //! Get the training error.
    double TrainingError() const { return trainingError; }

    //! Get the validation error.
    double ValidationError() const { return validationError; }

    //! Get whether or not the individual inputs are shuffled.
    bool Shuffle() const { return shuffle; }
    //! Modify whether or not the individual inputs are shuffled.
    bool& Shuffle() { return shuffle; }

    //! Get the batch size.
    size_t StepSize() const { return batchSize; }
    //! Modify the batch size.
    size_t& StepSize() { return batchSize; }

    //! Get the maximum number of iterations (0 indicates no limit).
    size_t MaxEpochs() const { return maxEpochs; }
    //! Modify the maximum number of iterations (0 indicates no limit).
    size_t& MaxEpochs() { return maxEpochs; }

    //! Get the tolerance for termination.
    double Tolerance() const { return tolerance; }
    //! Modify the tolerance for termination.
    double& Tolerance() { return tolerance; }

  private:
    /**
     * Train the network on the given dataset.
     *
     * @param data Data used to train the network.
     * @param target Labels used to train the network.
     */
    template<typename InputType, typename OutputType, typename ModelType>
    typename std::enable_if<!NetworkTraits<ModelType>::IsSAE, void>::type
    Train(InputType& data, OutputType& target)
    {
      // Reset the training error.
      trainingError = 0;

      for (size_t i = 0; i < index.n_elem; i++)
      {
        net.FeedForward(Element(data, index(i)),
            Element(target, index(i)), error);

        trainingError += net.Error();
        net.FeedBackward(Element(data, index(i)), error);

        if (((i + 1) % batchSize) == 0)
          net.ApplyGradients();
      }

      if ((index.n_elem % batchSize) != 0)
        net.ApplyGradients();

      trainingError /= index.n_elem;
    }

    /**
     * Train the sparse autoencoder on the given dataset.
     *
     * @param data Data used to train the network.
     */
    template<typename InputType, typename OutputType, typename ModelType>
    typename std::enable_if<NetworkTraits<ModelType>::IsSAE, void>::type
    Train(InputType& data, OutputType& /* unused */)
    {
      // Reset the training error.
      trainingError = 0;

      arma::uvec indices(batchSize);

      if (index.n_elem > batchSize)
      {
        for (size_t i = 0; i < index.n_elem; i += batchSize)
        {
          for (size_t j = 0; j < batchSize; j++)
            indices(j) = index(j + i);

          MatType input = data.rows(indices);
          net.FeedForward(input, input, error);

          trainingError += net.Error();
          net.FeedBackward(input, error);
          net.ApplyGradients();
        }

        trainingError /= (index.n_elem / batchSize);
      }
      else
      {
        net.FeedForward(data, data, error);
        trainingError += net.Error();
        net.FeedBackward(data, error);
        net.ApplyGradients();
      }
    }

    /**
     * Evaluate the network on the given dataset.
     *
     * @param data Data used to train the network.
     * @param target Labels used to train the network.
     */
    template<typename InputType, typename OutputType, typename ModelType>
    typename std::enable_if<!NetworkTraits<ModelType>::IsSAE, void>::type
    Evaluate(InputType& data, OutputType& target)
    {
      // Reset the validation error.
      validationError = 0;

      for (size_t i = 0; i < ElementCount(data); i++)
      {
         validationError += net.Evaluate(Element(data, i),
            Element(target, i), error);
      }

      validationError /= ElementCount(data);
    }

    template<typename InputType, typename OutputType, typename ModelType>
    typename std::enable_if<NetworkTraits<ModelType>::IsSAE, void>::type
    Evaluate(InputType& data, OutputType& target) { /* Nothing to do here */ }

    /*
     * Create a Col object which uses memory from an existing matrix object.
     * (This approach is currently not alias safe)
     *
     * @param data The reference data.
     * @param sliceNum Provide a Col object of the specified index.
     */
    template<typename eT>
    arma::Mat<eT> Element(arma::Mat<eT>& input, const size_t colNum)
    {
      return arma::Mat<eT>(input.colptr(colNum), input.n_rows, 1, false, true);
    }

    /*
     * Provide the reference to the matrix representing a single slice.
     *
     * @param data The reference data.
     * @param sliceNum Provide a single slice of the specified index.
     */
    template<typename eT>
    const arma::Cube<eT> Element(arma::Cube<eT>& input, const size_t sliceNum)
    {
      return input.slices(sliceNum, sliceNum);
    }

    /*
     * Get the number of elements.
     *
     * @param data The reference data.
     */
    template<typename eT>
    size_t ElementCount(const arma::Mat<eT>& data) const
    {
      return data.n_cols;
    }

    /*
     * Get the number of elements.
     *
     * @param data The reference data.
     */
    template<typename eT>
    size_t ElementCount(const arma::Cube<eT>& data) const
    {
      return data.n_slices;
    }

    //! The network which should be trained and evaluated.
    NetworkType& net;

    //! The current network error of a single input.
    MatType error;

    //! The current epoch if maxEpochs is set.
    size_t epoch;

    //! The maximal epochs that should be used.
    size_t maxEpochs;

    //! The size until a update is performed.
    size_t batchSize;

    //! The shuffel sequence index used to train the network.
    arma::Col<size_t> index;

    //! The overall traing error.
    double trainingError;

    //! The overall validation error.
    double validationError;

    //! The tolerance for termination.
    double tolerance;

    //! Controls whether or not the individual inputs are shuffled when
    //! iterating.
    bool shuffle;
}; // class Trainer

} // namespace ann
} // namespace mlpack

#endif
<commit_msg>Remove unused parameter.<commit_after>/**
 * @file trainer.hpp
 * @author Marcus Edel
 *
 * Definition and implementation of a trainer that trains the parameters of a
 * neural network according to a supervised dataset.
 */
#ifndef __MLPACK_METHODS_ANN_TRAINER_TRAINER_HPP
#define __MLPACK_METHODS_ANN_TRAINER_TRAINER_HPP

#include <mlpack/core.hpp>

#include <mlpack/methods/ann/network_traits.hpp>
#include <mlpack/methods/ann/layer/layer_traits.hpp>

namespace mlpack {
namespace ann /** Artificial Neural Network. */ {

/**
 * Trainer that trains the parameters of a neural network according to a
 * supervised dataset.
 *
 * @tparam NetworkType The type of network which should be trained and
 * evaluated.
 * @tparam MaType Type of the error type (arma::mat or arma::sp_mat).
 */
template<
  typename NetworkType,
  typename MatType = arma::mat
>
class Trainer
{
  public:
    /**
     * Construct the Trainer object, which will be used to train a neural
     * network according to a supervised dataset by backpropagating the errors.
     *
     * If batchSize is greater 1 the trainer will take a mean gradient step over
     * this many samples and will update the parameters only at the end of
     * each epoch (Default 1).
     *
     * @param net The network that should be trained.
     * @param maxEpochs The number of maximal trained iterations (0 means no
     * limit).
     * @param batchSize The batch size used to train the network.
     * @param tolerance Train the network until it converges against
     * the specified threshold.
     * @param shuffle If true, the order of the training set is shuffled;
     * otherwise, each data is visited in linear order.
     */
    Trainer(NetworkType& net,
            const size_t maxEpochs = 0,
            const size_t batchSize = 1,
            const double tolerance = 0.0001,
            const bool shuffle = true) :
        net(net),
        maxEpochs(maxEpochs),
        batchSize(batchSize),
        tolerance(tolerance),
        shuffle(shuffle)
    {
      // Nothing to do here.
    }

    /**
     * Train the network on the given datasets until the network converges. If
     * maxEpochs is greater than zero that many epochs are maximal trained.
     *
     * @param trainingData Data used to train the network.
     * @param trainingLabels Labels used to train the network.
     * @param validationData Data used to evaluate the network.
     * @tparam validationLabels Labels used to evaluate the network.
     */
    template<typename InputType, typename OutputType>
    void Train(InputType& trainingData,
               OutputType& trainingLabels,
               InputType& validationData,
               OutputType& validationLabels)
    {
      // This generates [0 1 2 3 ... (ElementCount(trainingData) - 1)]. The
      // sequence will be used to iterate through the training data.
      index = arma::linspace<arma::Col<size_t> >(0,
          ElementCount(trainingData) - 1, ElementCount(trainingData));
      epoch = 0;

      while(true)
      {
        if (shuffle)
          index = arma::shuffle(index);

        Train<InputType, OutputType, NetworkType>(
            trainingData, trainingLabels);
        Evaluate<InputType, OutputType, NetworkType>(
            validationData, validationLabels);

        if (validationError <= tolerance)
          break;

        if (maxEpochs > 0 && ++epoch >= maxEpochs)
          break;
      }
    }

    //! Get the training error.
    double TrainingError() const { return trainingError; }

    //! Get the validation error.
    double ValidationError() const { return validationError; }

    //! Get whether or not the individual inputs are shuffled.
    bool Shuffle() const { return shuffle; }
    //! Modify whether or not the individual inputs are shuffled.
    bool& Shuffle() { return shuffle; }

    //! Get the batch size.
    size_t StepSize() const { return batchSize; }
    //! Modify the batch size.
    size_t& StepSize() { return batchSize; }

    //! Get the maximum number of iterations (0 indicates no limit).
    size_t MaxEpochs() const { return maxEpochs; }
    //! Modify the maximum number of iterations (0 indicates no limit).
    size_t& MaxEpochs() { return maxEpochs; }

    //! Get the tolerance for termination.
    double Tolerance() const { return tolerance; }
    //! Modify the tolerance for termination.
    double& Tolerance() { return tolerance; }

  private:
    /**
     * Train the network on the given dataset.
     *
     * @param data Data used to train the network.
     * @param target Labels used to train the network.
     */
    template<typename InputType, typename OutputType, typename ModelType>
    typename std::enable_if<!NetworkTraits<ModelType>::IsSAE, void>::type
    Train(InputType& data, OutputType& target)
    {
      // Reset the training error.
      trainingError = 0;

      for (size_t i = 0; i < index.n_elem; i++)
      {
        net.FeedForward(Element(data, index(i)),
            Element(target, index(i)), error);

        trainingError += net.Error();
        net.FeedBackward(Element(data, index(i)), error);

        if (((i + 1) % batchSize) == 0)
          net.ApplyGradients();
      }

      if ((index.n_elem % batchSize) != 0)
        net.ApplyGradients();

      trainingError /= index.n_elem;
    }

    /**
     * Train the sparse autoencoder on the given dataset.
     *
     * @param data Data used to train the network.
     */
    template<typename InputType, typename OutputType, typename ModelType>
    typename std::enable_if<NetworkTraits<ModelType>::IsSAE, void>::type
    Train(InputType& data, OutputType& /* unused */)
    {
      // Reset the training error.
      trainingError = 0;

      arma::uvec indices(batchSize);

      if (index.n_elem > batchSize)
      {
        for (size_t i = 0; i < index.n_elem; i += batchSize)
        {
          for (size_t j = 0; j < batchSize; j++)
            indices(j) = index(j + i);

          MatType input = data.rows(indices);
          net.FeedForward(input, input, error);

          trainingError += net.Error();
          net.FeedBackward(input, error);
          net.ApplyGradients();
        }

        trainingError /= (index.n_elem / batchSize);
      }
      else
      {
        net.FeedForward(data, data, error);
        trainingError += net.Error();
        net.FeedBackward(data, error);
        net.ApplyGradients();
      }
    }

    /**
     * Evaluate the network on the given dataset.
     *
     * @param data Data used to train the network.
     * @param target Labels used to train the network.
     */
    template<typename InputType, typename OutputType, typename ModelType>
    typename std::enable_if<!NetworkTraits<ModelType>::IsSAE, void>::type
    Evaluate(InputType& data, OutputType& target)
    {
      // Reset the validation error.
      validationError = 0;

      for (size_t i = 0; i < ElementCount(data); i++)
      {
         validationError += net.Evaluate(Element(data, i),
            Element(target, i), error);
      }

      validationError /= ElementCount(data);
    }

    template<typename InputType, typename OutputType, typename ModelType>
    typename std::enable_if<NetworkTraits<ModelType>::IsSAE, void>::type
    Evaluate(InputType& /* unused */, OutputType& /* unused */) { /* Nothing to do here */ }

    /*
     * Create a Col object which uses memory from an existing matrix object.
     * (This approach is currently not alias safe)
     *
     * @param data The reference data.
     * @param sliceNum Provide a Col object of the specified index.
     */
    template<typename eT>
    arma::Mat<eT> Element(arma::Mat<eT>& input, const size_t colNum)
    {
      return arma::Mat<eT>(input.colptr(colNum), input.n_rows, 1, false, true);
    }

    /*
     * Provide the reference to the matrix representing a single slice.
     *
     * @param data The reference data.
     * @param sliceNum Provide a single slice of the specified index.
     */
    template<typename eT>
    const arma::Cube<eT> Element(arma::Cube<eT>& input, const size_t sliceNum)
    {
      return input.slices(sliceNum, sliceNum);
    }

    /*
     * Get the number of elements.
     *
     * @param data The reference data.
     */
    template<typename eT>
    size_t ElementCount(const arma::Mat<eT>& data) const
    {
      return data.n_cols;
    }

    /*
     * Get the number of elements.
     *
     * @param data The reference data.
     */
    template<typename eT>
    size_t ElementCount(const arma::Cube<eT>& data) const
    {
      return data.n_slices;
    }

    //! The network which should be trained and evaluated.
    NetworkType& net;

    //! The current network error of a single input.
    MatType error;

    //! The current epoch if maxEpochs is set.
    size_t epoch;

    //! The maximal epochs that should be used.
    size_t maxEpochs;

    //! The size until a update is performed.
    size_t batchSize;

    //! The shuffel sequence index used to train the network.
    arma::Col<size_t> index;

    //! The overall traing error.
    double trainingError;

    //! The overall validation error.
    double validationError;

    //! The tolerance for termination.
    double tolerance;

    //! Controls whether or not the individual inputs are shuffled when
    //! iterating.
    bool shuffle;
}; // class Trainer

} // namespace ann
} // namespace mlpack

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (c) 2016, Acer Yun-Tse Yang All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/
#include "gtest/gtest.h"
#include "sqlite3cpp.h"
#include <iostream>
#include <limits>

struct DBTest : ::testing::Test {
    DBTest()
    {}

    virtual ~DBTest() {}

    virtual void SetUp() {
        m_basic_dataset.reset(new sqlite3cpp::database(":memory:"));

        auto c = basic_dataset().make_cursor();
        c.executescript(
          "begin;"
          "create table T (a INTEGER, b TEXT);"
          "insert into T values(1, 'test1');"
          "insert into T values(2, 'test2');"
          "insert into T values(2, 'abc');"
          "insert into T values(3, 'test3');"
          "commit;"
          );
    }

    virtual void TearDown() {
        m_basic_dataset.reset();
    }

    sqlite3cpp::database &basic_dataset() {
        return *m_basic_dataset;
    }

private:
    std::unique_ptr<sqlite3cpp::database> m_basic_dataset;
};

TEST(basic, construct) {
    using namespace sqlite3cpp;
    database d(":memory:");
}

TEST_F(DBTest, row_iter) {
    using namespace sqlite3cpp;

    auto c = basic_dataset().make_cursor();

    c.executescript("create table Empty (a);");
    c.execute("select * from Empty");

    EXPECT_EQ(c.begin(), c.end());

    c.execute("insert into Empty values(?)", 123);
    c.execute("select * from Empty");

    EXPECT_NE(c.begin(), c.end());
    EXPECT_EQ(++c.begin(), c.end());
    EXPECT_EQ(c.begin(), c.end());
}

TEST_F(DBTest, bind_null) {
    auto c = basic_dataset().make_cursor();

    c.execute("create table T2 (a);");
    c.execute("insert into T2 values(?)", nullptr);
    c.execute("select count(*) from T2 where a is NULL");

    int cnt = 0;
    std::tie(cnt) = c.begin()->to<int>();
    EXPECT_EQ(1, cnt);
}

TEST_F(DBTest, query) {
    using namespace sqlite3cpp;
    auto c = basic_dataset().make_cursor();
    char const *query = "select * from T where a > ? and a < ? and b like ?";
    std::string pattern = "test%";

    int idx = 0;
    for(auto const &row : c.execute(query, 1, 3, "test%")) {
        int a; std::string b;
        std::tie(a, b) = row.to<int, std::string>();

        EXPECT_EQ(2, a);
        EXPECT_STREQ("test2", b.c_str());
    }
}

TEST(basic, wrap_function) {
    using namespace sqlite3cpp;
    using namespace std;
    using namespace std::placeholders;

    function<int(int)> c;
    auto f = detail::make_invoker(move(c));

    struct functor {
        void step(int x){ }
        int finalize(){
            return 0;
        }
    };
    functor fr;
    detail::bind_this(&functor::step, &fr);
}

TEST_F(DBTest, create_scalar) {
    using namespace sqlite3cpp;
    auto c = basic_dataset().make_cursor();

    struct minus_x {
        minus_x(int x) : m_x(x) {}
        int operator()(int input) const {
            return input - m_x;
        }
        int m_x;
    };
    basic_dataset().create_scalar("minus123", minus_x(123));

    int x = 123;
    basic_dataset().create_scalar("plus123", [x](int input) {
        return x + input;
    });

    basic_dataset().create_scalar("mutiply", [](int x, int y) {
        return x * y;
    });

    basic_dataset().create_scalar("strcat123", [](std::string val) {
        return val + "_123";
    });

    char const *query = "select plus123(a), mutiply(a,a), minus123(a), strcat123(a) from T;";

    int idx = 0;
    struct {
        int plus, mul, min;
        char const *cat;
    } expected[4] = {
        { 123+1, 1*1, 1 - 123, "1_123" },
        { 123+2, 2*2, 2 - 123, "2_123" },
        { 123+2, 2*2, 2 - 123, "2_123" },
        { 123+3, 3*3, 3 - 123, "3_123" }
    };

    for(auto const &row : c.execute(query)) {
        int a, b, c;
        std::string d;

        std::tie(a, b, c, d) = row.to<int, int, int, std::string>();
        EXPECT_EQ(expected[idx].plus, a);
        EXPECT_EQ(expected[idx].mul, b);
        EXPECT_EQ(expected[idx].min, c);
        EXPECT_EQ(expected[idx].cat, d);
        idx++;
    }
}

TEST_F(DBTest, max_int64) {
    auto c = basic_dataset().make_cursor();

    basic_dataset().create_scalar("maxint64", [](){
        return std::numeric_limits<int64_t>::max();
    });

    for(auto const &row : c.execute("select maxint64()")) {
        EXPECT_EQ(std::numeric_limits<int64_t>::max(),
                  std::get<0>(row.to<int64_t>()));
    }
}

TEST_F(DBTest, create_aggregate) {

    using namespace sqlite3cpp;

    struct stdev {
        void step(int val) {
            m_cnt ++;
            m_sum += val;
            m_sq_sum += val * val;

        }
        double finalize() {
            auto avg = (double)m_sum / m_cnt;
            return std::sqrt((double)(m_sq_sum - avg * avg * m_cnt) / (m_cnt -1));
        }
        size_t m_cnt = 0;
        int m_sum = 0,
            m_sq_sum = 0;
    };

    basic_dataset().create_aggregate<stdev>("stdev");
    auto c = basic_dataset().make_cursor();

    char const *query = "select stdev(a) from T";
    for(auto const &row : c.execute(query)) {
        double a;
        std::tie(a) = row.to<double>();
        // XXX Platfomr dependant
        EXPECT_DOUBLE_EQ(0.81649658092772603, a);
    }
}

TEST_F(DBTest, error_handle) {
    using namespace sqlite3cpp;

    auto c = basic_dataset().make_cursor();

    try {
        c.execute("invalid sql");
        FAIL() << "Expect throw";
    } catch(error const &e) {
        EXPECT_EQ(SQLITE_ERROR, e.code);
        EXPECT_STREQ("SQL logic error or missing database", e.what());
    } catch(...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    try {
        c.executescript("invalid sql");
        FAIL() << "Expect throw";
    } catch(error const &e) {
        EXPECT_EQ(SQLITE_ERROR, e.code);
        EXPECT_STREQ("SQL logic error or missing database", e.what());
    } catch(...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    try {
        c.execute("select * from T", 123); // invalid bind
    } catch(error const &e) {
        EXPECT_EQ(SQLITE_RANGE, e.code);
        EXPECT_STREQ("bind or column index out of range", e.what());
    } catch(...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }
}

TEST_F(DBTest, throw_in_custom_function) {

    auto c = basic_dataset().make_cursor();

    basic_dataset().create_scalar("bad_alloc", [](){
        throw std::bad_alloc();
    });

    try {
        c.execute("select bad_alloc();");
    } catch(sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_NOMEM, e.code);
        EXPECT_STREQ("out of memory", e.what());
    }  catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    basic_dataset().create_scalar("length_error", [](){
        throw std::length_error("len err");
    });

    try {
        c.execute("select length_error();");
    } catch(sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_ABORT, e.code);
        EXPECT_STREQ("callback requested query abort", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

}

TEST_F(DBTest, logic_error_in_aggregate) {

    auto c = basic_dataset().make_cursor();

    struct throw_in_step {
        void step(int a) {
            throw std::out_of_range("oops");
        }
        int finalize() {
            return 0;
        }
    };

    basic_dataset().create_aggregate<throw_in_step>("throw_in_step");

    try {
        c.execute("select throw_in_step(a) from T");
    } catch (sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_ABORT, e.code);
        EXPECT_STREQ("callback requested query abort", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    struct throw_in_final {
        void step(int a){}
        int finalize() {
            throw std::out_of_range("oops");
            return 0;
        }
    };

    basic_dataset().create_aggregate<throw_in_final>("throw_in_final");

    try {
        c.execute("select throw_in_final(a) from T");
    } catch (sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_ABORT, e.code);
        EXPECT_STREQ("callback requested query abort", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }
}

TEST_F(DBTest, bad_alloc_in_aggregate) {

    auto c = basic_dataset().make_cursor();

    struct throw_in_step {
        void step(int a) {
            throw std::bad_alloc();
        }
        int finalize() {
            return 0;
        }
    };

    basic_dataset().create_aggregate<throw_in_step>("throw_in_step");

    try {
        c.execute("select throw_in_step(a) from T");
    } catch (sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_NOMEM, e.code);
        EXPECT_STREQ("out of memory", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    struct throw_in_final {
        void step(int a){}
        int finalize() {
            throw std::bad_alloc();
            return 0;
        }
    };

    basic_dataset().create_aggregate<throw_in_final>("throw_in_final");

    try {
        c.execute("select throw_in_final(a) from T");
    } catch (sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_NOMEM, e.code);
        EXPECT_STREQ("out of memory", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }
}

# include "version.h"

TEST_F(DBTest, version) {

    EXPECT_STREQ(SQLITE3CPP_VERSION_STRING, basic_dataset().version().c_str());
}
<commit_msg>Add string_ref test.<commit_after>/*****************************************************************************
 * Copyright (c) 2016, Acer Yun-Tse Yang All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/
#include "gtest/gtest.h"
#include "sqlite3cpp.h"
#include <iostream>
#include <limits>

struct DBTest : ::testing::Test {
    DBTest()
    {}

    virtual ~DBTest() {}

    virtual void SetUp() {
        m_basic_dataset.reset(new sqlite3cpp::database(":memory:"));

        auto c = basic_dataset().make_cursor();
        c.executescript(
          "begin;"
          "create table T (a INTEGER, b TEXT);"
          "insert into T values(1, 'test1');"
          "insert into T values(2, 'test2');"
          "insert into T values(2, 'abc');"
          "insert into T values(3, 'test3');"
          "commit;"
          );
    }

    virtual void TearDown() {
        m_basic_dataset.reset();
    }

    sqlite3cpp::database &basic_dataset() {
        return *m_basic_dataset;
    }

private:
    std::unique_ptr<sqlite3cpp::database> m_basic_dataset;
};

TEST(basic, construct) {
    using namespace sqlite3cpp;
    database d(":memory:");
}

TEST_F(DBTest, row_iter) {
    using namespace sqlite3cpp;

    auto c = basic_dataset().make_cursor();

    c.executescript("create table Empty (a);");
    c.execute("select * from Empty");

    EXPECT_EQ(c.begin(), c.end());

    c.execute("insert into Empty values(?)", 123);
    c.execute("select * from Empty");

    EXPECT_NE(c.begin(), c.end());
    EXPECT_EQ(++c.begin(), c.end());
    EXPECT_EQ(c.begin(), c.end());
}

TEST_F(DBTest, bind_null) {
    auto c = basic_dataset().make_cursor();

    c.execute("create table T2 (a);");
    c.execute("insert into T2 values(?)", nullptr);
    c.execute("select count(*) from T2 where a is NULL");

    int cnt = 0;
    std::tie(cnt) = c.begin()->to<int>();
    EXPECT_EQ(1, cnt);
}

TEST_F(DBTest, query) {
    using namespace sqlite3cpp;
    auto c = basic_dataset().make_cursor();
    char const *query = "select * from T where a > ? and a < ? and b like ?";
    std::string pattern = "test%";

    int idx = 0;
    for(auto const &row : c.execute(query, 1, 3, "test%")) {
        int a; std::string b;
        std::tie(a, b) = row.to<int, std::string>();

        EXPECT_EQ(2, a);
        EXPECT_STREQ("test2", b.c_str());
    }
}

TEST_F(DBTest, query_with_string_ref) {
    using namespace sqlite3cpp;

    auto c = basic_dataset().make_cursor();
    char const *query = "select * from T where a > ? and a < ? and b like ?";
    std::string pattern = "test%";

    int idx = 0;
    for(auto const &row : c.execute(query, 1, 3, "test%")) {
        int a; string_ref b;
        std::tie(a, b) = row.to<int, string_ref>();

        EXPECT_EQ(2, a);
        EXPECT_STREQ("test2", b.data());
    }
}

TEST(basic, wrap_function) {
    using namespace sqlite3cpp;
    using namespace std;
    using namespace std::placeholders;

    function<int(int)> c;
    auto f = detail::make_invoker(move(c));

    struct functor {
        void step(int x){ }
        int finalize(){
            return 0;
        }
    };
    functor fr;
    detail::bind_this(&functor::step, &fr);
}

TEST_F(DBTest, create_scalar) {
    using namespace sqlite3cpp;
    auto c = basic_dataset().make_cursor();

    struct minus_x {
        minus_x(int x) : m_x(x) {}
        int operator()(int input) const {
            return input - m_x;
        }
        int m_x;
    };
    basic_dataset().create_scalar("minus123", minus_x(123));

    int x = 123;
    basic_dataset().create_scalar("plus123", [x](int input) {
        return x + input;
    });

    basic_dataset().create_scalar("mutiply", [](int x, int y) {
        return x * y;
    });

    basic_dataset().create_scalar("strcat123", [](std::string val) {
        return val + "_123";
    });

    char const *query = "select plus123(a), mutiply(a,a), minus123(a), strcat123(a) from T;";

    int idx = 0;
    struct {
        int plus, mul, min;
        char const *cat;
    } expected[4] = {
        { 123+1, 1*1, 1 - 123, "1_123" },
        { 123+2, 2*2, 2 - 123, "2_123" },
        { 123+2, 2*2, 2 - 123, "2_123" },
        { 123+3, 3*3, 3 - 123, "3_123" }
    };

    for(auto const &row : c.execute(query)) {
        int a, b, c;
        std::string d;

        std::tie(a, b, c, d) = row.to<int, int, int, std::string>();
        EXPECT_EQ(expected[idx].plus, a);
        EXPECT_EQ(expected[idx].mul, b);
        EXPECT_EQ(expected[idx].min, c);
        EXPECT_EQ(expected[idx].cat, d);
        idx++;
    }
}

TEST_F(DBTest, max_int64) {
    auto c = basic_dataset().make_cursor();

    basic_dataset().create_scalar("maxint64", [](){
        return std::numeric_limits<int64_t>::max();
    });

    for(auto const &row : c.execute("select maxint64()")) {
        EXPECT_EQ(std::numeric_limits<int64_t>::max(),
                  std::get<0>(row.to<int64_t>()));
    }
}

TEST_F(DBTest, create_aggregate) {

    using namespace sqlite3cpp;

    struct stdev {
        void step(int val) {
            m_cnt ++;
            m_sum += val;
            m_sq_sum += val * val;

        }
        double finalize() {
            auto avg = (double)m_sum / m_cnt;
            return std::sqrt((double)(m_sq_sum - avg * avg * m_cnt) / (m_cnt -1));
        }
        size_t m_cnt = 0;
        int m_sum = 0,
            m_sq_sum = 0;
    };

    basic_dataset().create_aggregate<stdev>("stdev");
    auto c = basic_dataset().make_cursor();

    char const *query = "select stdev(a) from T";
    for(auto const &row : c.execute(query)) {
        double a;
        std::tie(a) = row.to<double>();
        // XXX Platfomr dependant
        EXPECT_DOUBLE_EQ(0.81649658092772603, a);
    }
}

TEST_F(DBTest, error_handle) {
    using namespace sqlite3cpp;

    auto c = basic_dataset().make_cursor();

    try {
        c.execute("invalid sql");
        FAIL() << "Expect throw";
    } catch(error const &e) {
        EXPECT_EQ(SQLITE_ERROR, e.code);
        EXPECT_STREQ("SQL logic error or missing database", e.what());
    } catch(...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    try {
        c.executescript("invalid sql");
        FAIL() << "Expect throw";
    } catch(error const &e) {
        EXPECT_EQ(SQLITE_ERROR, e.code);
        EXPECT_STREQ("SQL logic error or missing database", e.what());
    } catch(...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    try {
        c.execute("select * from T", 123); // invalid bind
    } catch(error const &e) {
        EXPECT_EQ(SQLITE_RANGE, e.code);
        EXPECT_STREQ("bind or column index out of range", e.what());
    } catch(...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }
}

TEST_F(DBTest, throw_in_custom_function) {

    auto c = basic_dataset().make_cursor();

    basic_dataset().create_scalar("bad_alloc", [](){
        throw std::bad_alloc();
    });

    try {
        c.execute("select bad_alloc();");
    } catch(sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_NOMEM, e.code);
        EXPECT_STREQ("out of memory", e.what());
    }  catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    basic_dataset().create_scalar("length_error", [](){
        throw std::length_error("len err");
    });

    try {
        c.execute("select length_error();");
    } catch(sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_ABORT, e.code);
        EXPECT_STREQ("callback requested query abort", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

}

TEST_F(DBTest, logic_error_in_aggregate) {

    auto c = basic_dataset().make_cursor();

    struct throw_in_step {
        void step(int a) {
            throw std::out_of_range("oops");
        }
        int finalize() {
            return 0;
        }
    };

    basic_dataset().create_aggregate<throw_in_step>("throw_in_step");

    try {
        c.execute("select throw_in_step(a) from T");
    } catch (sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_ABORT, e.code);
        EXPECT_STREQ("callback requested query abort", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    struct throw_in_final {
        void step(int a){}
        int finalize() {
            throw std::out_of_range("oops");
            return 0;
        }
    };

    basic_dataset().create_aggregate<throw_in_final>("throw_in_final");

    try {
        c.execute("select throw_in_final(a) from T");
    } catch (sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_ABORT, e.code);
        EXPECT_STREQ("callback requested query abort", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }
}

TEST_F(DBTest, bad_alloc_in_aggregate) {

    auto c = basic_dataset().make_cursor();

    struct throw_in_step {
        void step(int a) {
            throw std::bad_alloc();
        }
        int finalize() {
            return 0;
        }
    };

    basic_dataset().create_aggregate<throw_in_step>("throw_in_step");

    try {
        c.execute("select throw_in_step(a) from T");
    } catch (sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_NOMEM, e.code);
        EXPECT_STREQ("out of memory", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }

    struct throw_in_final {
        void step(int a){}
        int finalize() {
            throw std::bad_alloc();
            return 0;
        }
    };

    basic_dataset().create_aggregate<throw_in_final>("throw_in_final");

    try {
        c.execute("select throw_in_final(a) from T");
    } catch (sqlite3cpp::error const &e) {
        EXPECT_EQ(SQLITE_NOMEM, e.code);
        EXPECT_STREQ("out of memory", e.what());
    } catch (...) {
        FAIL() << "sqlite3cpp::error should be caught";
    }
}

# include "version.h"

TEST_F(DBTest, version) {

    EXPECT_STREQ(SQLITE3CPP_VERSION_STRING, basic_dataset().version().c_str());
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <string.h>

#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/byte_buffer_reader.h"
#include "grpc/support/slice.h"
#include "grpc/support/log.h"

#include "byte_buffer.h"

namespace grpc {
namespace node {

using v8::Context;
using v8::Function;
using v8::Local;
using v8::Object;
using v8::Number;
using v8::Value;

grpc_byte_buffer *BufferToByteBuffer(Local<Value> buffer) {
  Nan::HandleScope scope;
  int length = ::node::Buffer::Length(buffer);
  char *data = ::node::Buffer::Data(buffer);
  gpr_slice slice = gpr_slice_malloc(length);
  memcpy(GPR_SLICE_START_PTR(slice), data, length);
  grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1));
  gpr_slice_unref(slice);
  return byte_buffer;
}

namespace {
void delete_buffer(char *data, void *hint) { delete[] data; }
}

Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
  Nan::EscapableHandleScope scope;
  if (buffer == NULL) {
    return scope.Escape(Nan::Null());
  }
  gpr_log(GPR_DEBUG, "Compressed size: %d", grpc_byte_buffer_length(buffer));
  grpc_byte_buffer_reader reader;
  grpc_byte_buffer_reader_init(&reader, buffer);
  gpr_slice slice = grpc_byte_buffer_reader_readall(&reader);
  size_t length = GPR_SLICE_LENGTH(slice);
  char *result = new char[length];
  memcpy(result, GPR_SLICE_START_PTR(slice), length);
  return scope.Escape(MakeFastBuffer(
      Nan::NewBuffer(result, length, delete_buffer, NULL).ToLocalChecked()));
}

Local<Value> MakeFastBuffer(Local<Value> slowBuffer) {
  Nan::EscapableHandleScope scope;
  Local<Object> globalObj = Nan::GetCurrentContext()->Global();
  Local<Function> bufferConstructor = Local<Function>::Cast(
      globalObj->Get(Nan::New("Buffer").ToLocalChecked()));
  Local<Value> consArgs[3] = {
    slowBuffer,
    Nan::New<Number>(::node::Buffer::Length(slowBuffer)),
    Nan::New<Number>(0)
  };
  Local<Object> fastBuffer = bufferConstructor->NewInstance(3, consArgs);
  return scope.Escape(fastBuffer);
}
}  // namespace node
}  // namespace grpc
<commit_msg>Remove extraneous logging code<commit_after>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <string.h>

#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/byte_buffer_reader.h"
#include "grpc/support/slice.h"

#include "byte_buffer.h"

namespace grpc {
namespace node {

using v8::Context;
using v8::Function;
using v8::Local;
using v8::Object;
using v8::Number;
using v8::Value;

grpc_byte_buffer *BufferToByteBuffer(Local<Value> buffer) {
  Nan::HandleScope scope;
  int length = ::node::Buffer::Length(buffer);
  char *data = ::node::Buffer::Data(buffer);
  gpr_slice slice = gpr_slice_malloc(length);
  memcpy(GPR_SLICE_START_PTR(slice), data, length);
  grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1));
  gpr_slice_unref(slice);
  return byte_buffer;
}

namespace {
void delete_buffer(char *data, void *hint) { delete[] data; }
}

Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
  Nan::EscapableHandleScope scope;
  if (buffer == NULL) {
    return scope.Escape(Nan::Null());
  }
  grpc_byte_buffer_reader reader;
  grpc_byte_buffer_reader_init(&reader, buffer);
  gpr_slice slice = grpc_byte_buffer_reader_readall(&reader);
  size_t length = GPR_SLICE_LENGTH(slice);
  char *result = new char[length];
  memcpy(result, GPR_SLICE_START_PTR(slice), length);
  return scope.Escape(MakeFastBuffer(
      Nan::NewBuffer(result, length, delete_buffer, NULL).ToLocalChecked()));
}

Local<Value> MakeFastBuffer(Local<Value> slowBuffer) {
  Nan::EscapableHandleScope scope;
  Local<Object> globalObj = Nan::GetCurrentContext()->Global();
  Local<Function> bufferConstructor = Local<Function>::Cast(
      globalObj->Get(Nan::New("Buffer").ToLocalChecked()));
  Local<Value> consArgs[3] = {
    slowBuffer,
    Nan::New<Number>(::node::Buffer::Length(slowBuffer)),
    Nan::New<Number>(0)
  };
  Local<Object> fastBuffer = bufferConstructor->NewInstance(3, consArgs);
  return scope.Escape(fastBuffer);
}
}  // namespace node
}  // namespace grpc
<|endoftext|>