<commit_before>#include "RayTracer.hpp"
#include "Tree.hpp"
#include <ctime>

//temporary variables
Vec3Df testRayOrigin;
Vec3Df testRayDestination;
string mesh;
extern unsigned int textures[2];
clock_t lastFrameTime;
float fps;
unsigned int framesSinceLastDraw = 30;
string screenFPS;
extern unsigned int previewResX;
extern unsigned int previewResY;
extern unsigned int msaa;
extern unsigned int numThreads;
extern Tree MyTree;

//use this function for any preprocessing of the mesh.
int init(int argc, char **argv){
    // skip program name argv[0] if present
    argc -= (argc > 0);
    argv += (argc > 0);

    option::Stats stats(usage, argc, argv);
    option::Option* options = (option::Option*)calloc(stats.options_max,
            sizeof(option::Option));
    option::Option* buffer = (option::Option*)calloc(stats.buffer_max,
            sizeof(option::Option));

    option::Parser parse(usage, argc, argv, options, buffer);

    if(parse.error())
        return 1;

    if(options[HELP]){
        int columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80;
        option::printUsage(fwrite, stdout, usage, columns);
        return 2;
    }

    lastFrameTime = clock();

    if(options[MESH]){
        const char* arg = options[MESH].last()->arg;
        if(arg != 0){
            mesh = arg;
        }
    }else{
        mesh = "0";
    }

    if(mesh == "0")
        mesh = "cube";
    else if(mesh == "1")
        mesh = "simple_monkey";
    else if(mesh == "2")
        mesh = "monkey";
    else if(mesh == "3")
        mesh = "dodgeColorTest";

    mesh = string("mesh/").append(mesh).append(".obj");
    MyMesh.loadMesh(mesh.c_str(), true);
    MyMesh.computeVertexNormals();
	MyTree.build(MyMesh);

    //one first move: initialize the first light source
    //at least ONE light source has to be in the scene!!!
    //here, we set it to the current location of the camera
    MyLightPositions.push_back(MyCameraPosition);

    if(options[RAYTRACE]){
        startRayTracing(activeTexIndex, true);
        return 255;
    }

    return 0;
}

//transformer le x, y en position 3D
void produceRay(int x_I, int y_I, Vec3Df * origin, Vec3Df * dest){
    int viewport[4];
    double modelview[16];
    double projection[16];
    //point sur near plane
    //double positionN[3];
    //point sur far plane
    //double positionF[3];
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview); //recuperer matrices
    glGetDoublev(GL_PROJECTION_MATRIX, projection); //recuperer matrices
    glGetIntegerv(GL_VIEWPORT, viewport); //viewport
    int y_new = viewport[3] - y_I;

    double x, y, z;

    gluUnProject(x_I, y_new, 0, modelview, projection, viewport, &x, &y, &z);
    origin->p[0] = float(x);
    origin->p[1] = float(y);
    origin->p[2] = float(z);
    gluUnProject(x_I, y_new, 1, modelview, projection, viewport, &x, &y, &z);
    dest->p[0] = float(x);
    dest->p[1] = float(y);
    dest->p[2] = float(z);
}

void produceRay(int x_I, int y_I, Vec3Df & origin, Vec3Df & dest){
    produceRay(x_I, y_I, &origin, &dest);
}

Vec3Df origin00, dest00;
Vec3Df origin01, dest01;
Vec3Df origin10, dest10;
Vec3Df origin11, dest11;
#ifdef WIN32
#define linux false
#else
#define linux true
#endif

void raytracePart(Image* result, int w, int h, int xx, int yy, int ww, int hh){
    Vec3Df origin, dest;
    for(float y = yy;y < hh;y++){
        for(float x = xx;x < ww;x++){
            //svp, decidez vous memes quels parametres vous allez passer à la fonction
            //c'est le stront a la plafond, c'est drôle
            //e.g., maillage, triangles, sphères etc.
            Vec3Df total(0, 0, 0);
            for(unsigned int xs = 0;xs < msaa;xs++){
                for(unsigned int ys = 0;ys < msaa;ys++){

                    float xscale = 1.0f - (x + float(xs) / msaa) / (w - 1);
                    float yscale = float(y + float(ys) / msaa) / (h - 1);
                    if(linux)
                    	yscale = 1.0f - yscale;
                    origin = yscale
                            * (xscale * origin00 + (1 - xscale) * origin10)
                            + (1 - yscale)
                                    * (xscale * origin01
                                            + (1 - xscale) * origin11);
                    dest = yscale * (xscale * dest00 + (1 - xscale) * dest10)
                            + (1 - yscale)
                                    * (xscale * dest01 + (1 - xscale) * dest11);

                    total += performRayTracing(origin, dest);
                }
            }

            // calculate average color
            total /= msaa * msaa;
            // result->_image
            result->_image[(y * result->_width + x) * 3 + 0] = total[0];
            result->_image[(y * result->_width + x) * 3 + 1] = total[1];
            result->_image[(y * result->_width + x) * 3 + 2] = total[2];
        }
    }
}

void startRayTracing(int texIndex, bool verbose){
    if(verbose)
        cout << "Raytracing" << endl;
    int w = RayTracingResolutionX;
    int h = RayTracingResolutionY;
    if(!verbose)
        w = previewResX;
    if(!verbose)
        h = previewResY;
    Image result(w, h);

    produceRay(0, 0, &origin00, &dest00);
    produceRay(0, WindowSizeX - 1, &origin01, &dest01);
    produceRay(WindowSizeX - 1, 0, &origin10, &dest10);
    produceRay(WindowSizeX - 1, WindowSizeY - 1, &origin11, &dest11);

    // Perform timing
    time_t start, end, ticks;
    start = clock();

    // multithread
#if THREADS != 0
    std::thread** th = (std::thread**)alloca(numThreads * sizeof(std::thread*));
    int subw = w / numThreads;

    for(unsigned int i = 0;i < numThreads;i++)
		th[i] = new std::thread(raytracePart, &result, w, h, i * subw, 0,
            (i + 1) * subw, h);			// i * subw, 0, subw, h);

    // wait for them to finish
    for(unsigned int i = 0;i < numThreads;i++)
		th[i]->join();

    // kill them all
    for(unsigned int i = 0;i < numThreads;i++)
		delete th[i];
#else
    raytracePart(&result, w, h, 0, 0, w, h);
#endif

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    start = end;
    int millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Rendering took %d ms cpu seconds and %d ms wall time\n",
                millis, millis/max(4, 1));

    // write to texture
    glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_FLOAT,
            &result._image[0]);

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Uploading to GPU took %d ms\n", millis);

    if(verbose)
        result.writeImage("result");
}

#define VEWY_HIGH 10e6f

Vec3Df black(0, 0, 0);

//return the color of your pixel.
Vec3Df performRayTracing(const Vec3Df & origin, const Vec3Df & dest){
    Ray ray = Ray(black, origin, dest);

	// calculate nearest triangle
	Triangle* triangle;
	float dist = MyTree.collide(ray, &triangle);
	Vec3Df light(1, 1, 1);
	Vec3Df orig2 = origin + ray.dir * dist;
	Vec3Df tolight = light - orig2;

	float angle = dot(orig2, tolight) * 2;

	return Vec3Df(angle, angle, angle * 0.5f);
}

void yourDebugDraw(){
    //draw open gl debug stuff
    //this function is called every frame

    drawFPS();

    //as an example:
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glDisable(GL_LIGHTING);
    glColor3f(1, 0, 1);
    glBegin(GL_LINES);
    glVertex3f(testRayOrigin[0], testRayOrigin[1], testRayOrigin[2]);
    glVertex3f(testRayDestination[0], testRayDestination[1],
            testRayDestination[2]);
    glEnd();
    glPointSize(10);
    glBegin(GL_POINTS);
    glVertex3fv(MyLightPositions[0].pointer());
    glEnd();
    glPopAttrib();

}

void yourKeyboardFunc(char t, int x, int y){
    // do what you want with the keyboard input t.
    // x, y are the screen position

    //here I use it to get the coordinates of a ray, which I then draw in the debug function.
    produceRay(x, y, testRayOrigin, testRayDestination);

    std::cout << t << " pressed! The mouse was in location " << x << "," << y
            << "!" << std::endl;
}

void drawFPS(){
    clock_t diff = clock() - lastFrameTime;
    lastFrameTime = clock();
    fps = 1 / ((float)diff / (float)CLOCKS_PER_SEC);

    if(framesSinceLastDraw++ > 29){
        framesSinceLastDraw = 0;
        screenFPS = to_string((int)fps);
    }

    glLoadIdentity();
    //glRasterPos2f(1.0f, 1.0f); // FPS draws on the lefthand bottom side of the screen now, if anyone knows how to get it to the lefthand top of the screen please fix it ;)
    for(unsigned int i = 0;i < screenFPS.length();i++){
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, screenFPS[i]);
    }
}
<commit_msg>M'erge branch 'master' of https://github.com/WoLpH/computer_graphics<commit_after>#include "RayTracer.hpp"
#include "Tree.hpp"
#include <ctime>

//temporary variables
Vec3Df testRayOrigin;
Vec3Df testRayDestination;
string mesh;
extern unsigned int textures[2];
clock_t lastFrameTime;
float fps;
unsigned int framesSinceLastDraw = 30;
string screenFPS;
extern unsigned int previewResX;
extern unsigned int previewResY;
extern unsigned int msaa;
extern unsigned int numThreads;
extern Tree MyTree;

//use this function for any preprocessing of the mesh.
int init(int argc, char **argv){
    // skip program name argv[0] if present
    argc -= (argc > 0);
    argv += (argc > 0);

    option::Stats stats(usage, argc, argv);
    option::Option* options = (option::Option*)calloc(stats.options_max,
            sizeof(option::Option));
    option::Option* buffer = (option::Option*)calloc(stats.buffer_max,
            sizeof(option::Option));

    option::Parser parse(usage, argc, argv, options, buffer);

    if(parse.error())
        return 1;

    if(options[HELP]){
        int columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80;
        option::printUsage(fwrite, stdout, usage, columns);
        return 2;
    }

    lastFrameTime = clock();

    if(options[MESH]){
        const char* arg = options[MESH].last()->arg;
        if(arg != 0){
            mesh = arg;
        }
    }else{
        mesh = "0";
    }

    if(mesh == "0")
        mesh = "cube";
    else if(mesh == "1")
        mesh = "simple_monkey";
    else if(mesh == "2")
        mesh = "monkey";
    else if(mesh == "3")
        mesh = "dodgeColorTest";

    mesh = string("mesh/").append(mesh).append(".obj");
    MyMesh.loadMesh(mesh.c_str(), true);
    MyMesh.computeVertexNormals();
    MyTree.build(MyMesh);

    //one first move: initialize the first light source
    //at least ONE light source has to be in the scene!!!
    //here, we set it to the current location of the camera
    MyLightPositions.push_back(MyCameraPosition);

    if(options[RAYTRACE]){
        startRayTracing(activeTexIndex, true);
        return 255;
    }

    return 0;
}

//transformer le x, y en position 3D
void produceRay(int x_I, int y_I, Vec3Df * origin, Vec3Df * dest){
    int viewport[4];
    double modelview[16];
    double projection[16];
    //point sur near plane
    //double positionN[3];
    //point sur far plane
    //double positionF[3];
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview); //recuperer matrices
    glGetDoublev(GL_PROJECTION_MATRIX, projection); //recuperer matrices
    glGetIntegerv(GL_VIEWPORT, viewport); //viewport
    int y_new = viewport[3] - y_I;

    double x, y, z;

    gluUnProject(x_I, y_new, 0, modelview, projection, viewport, &x, &y, &z);
    origin->p[0] = float(x);
    origin->p[1] = float(y);
    origin->p[2] = float(z);
    gluUnProject(x_I, y_new, 1, modelview, projection, viewport, &x, &y, &z);
    dest->p[0] = float(x);
    dest->p[1] = float(y);
    dest->p[2] = float(z);
}

void produceRay(int x_I, int y_I, Vec3Df & origin, Vec3Df & dest){
    produceRay(x_I, y_I, &origin, &dest);
}

Vec3Df origin00, dest00;
Vec3Df origin01, dest01;
Vec3Df origin10, dest10;
Vec3Df origin11, dest11;

void raytracePart(Image* result, int w, int h, int xx, int yy, int ww, int hh){
    Vec3Df origin, dest;
    for(float y = yy;y < hh;y++){
        for(float x = xx;x < ww;x++){
            //svp, decidez vous memes quels parametres vous allez passer à la fonction
            //c'est le stront a la plafond, c'est drôle
            //e.g., maillage, triangles, sphères etc.
            Vec3Df total(0, 0, 0);
            for(unsigned int xs = 0;xs < msaa;xs++){
                for(unsigned int ys = 0;ys < msaa;ys++){

                    float xscale = 1.0f - (x + float(xs) / msaa) / (w - 1);
                    float yscale = float(y + float(ys) / msaa) / (h - 1);
#ifdef LINUX
                    yscale = 1.0f - yscale;
#endif
                    origin = yscale
                            * (xscale * origin00 + (1 - xscale) * origin10)
                            + (1 - yscale)
                                    * (xscale * origin01
                                            + (1 - xscale) * origin11);
                    dest = yscale * (xscale * dest00 + (1 - xscale) * dest10)
                            + (1 - yscale)
                                    * (xscale * dest01 + (1 - xscale) * dest11);

                    total += performRayTracing(origin, dest);
                }
            }

            // calculate average color
            total /= msaa * msaa;
            // result->_image
            result->_image[(y * result->_width + x) * 3 + 0] = total[0];
            result->_image[(y * result->_width + x) * 3 + 1] = total[1];
            result->_image[(y * result->_width + x) * 3 + 2] = total[2];
        }
    }
}

void startRayTracing(int texIndex, bool verbose){
    if(verbose)
        cout << "Raytracing" << endl;
    int w = RayTracingResolutionX;
    int h = RayTracingResolutionY;
    if(!verbose)
        w = previewResX;
    if(!verbose)
        h = previewResY;
    Image result(w, h);

    produceRay(0, 0, &origin00, &dest00);
    produceRay(0, WindowSizeX - 1, &origin01, &dest01);
    produceRay(WindowSizeX - 1, 0, &origin10, &dest10);
    produceRay(WindowSizeX - 1, WindowSizeY - 1, &origin11, &dest11);

    // Perform timing
    time_t start, end, ticks;
    start = clock();

    // multithread
#if THREADS != 0
    std::thread** th = (std::thread**)alloca(numThreads * sizeof(std::thread*));
    int subw = w / numThreads;

    for(unsigned int i = 0;i < numThreads;i++)
    th[i] = new std::thread(raytracePart, &result, w, h, i * subw, 0,
            (i + 1) * subw, h);			// i * subw, 0, subw, h);

    // wait for them to finish
    for(unsigned int i = 0;i < numThreads;i++)
    th[i]->join();

    // kill them all
    for(unsigned int i = 0;i < numThreads;i++)
    delete th[i];
#else
    raytracePart(&result, w, h, 0, 0, w, h);
#endif

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    start = end;
    int millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Rendering took %d ms cpu seconds and %d ms wall time\n", millis,
                millis / max(numThreads, 1u));

    // write to texture
    glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_FLOAT,
            &result._image[0]);

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Uploading to GPU took %d ms\n", millis);

    if(verbose)
        result.writeImage("result");
}

#define VEWY_HIGH 10e6f

Vec3Df black(0, 0, 0);

//return the color of your pixel.
Vec3Df performRayTracing(const Vec3Df & origin, const Vec3Df & dest){
    Ray ray = Ray(black, origin, dest);

	// calculate nearest triangle
	Triangle* triangle;
	float dist = MyTree.collide(ray, &triangle);
	Vec3Df light(1, 1, 1);
	Vec3Df orig2 = origin + ray.dir * dist;
	Vec3Df tolight = light - orig2;

	float angle = dot(orig2, tolight) * 2;

	return Vec3Df(angle, angle, angle * 0.5f);
}

void yourDebugDraw(){
    //draw open gl debug stuff
    //this function is called every frame

    drawFPS();

    //as an example:
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glDisable(GL_LIGHTING);
    glColor3f(1, 0, 1);
    glBegin(GL_LINES);
    glVertex3f(testRayOrigin[0], testRayOrigin[1], testRayOrigin[2]);
    glVertex3f(testRayDestination[0], testRayDestination[1],
            testRayDestination[2]);
    glEnd();
    glPointSize(10);
    glBegin(GL_POINTS);
    glVertex3fv(MyLightPositions[0].pointer());
    glEnd();
    glPopAttrib();

}

void yourKeyboardFunc(char t, int x, int y){
    // do what you want with the keyboard input t.
    // x, y are the screen position

    //here I use it to get the coordinates of a ray, which I then draw in the debug function.
    produceRay(x, y, testRayOrigin, testRayDestination);

    std::cout << t << " pressed! The mouse was in location " << x << "," << y
            << "!" << std::endl;
}

void drawFPS(){
    clock_t diff = clock() - lastFrameTime;
    lastFrameTime = clock();
    fps = 1 / ((float)diff / (float)CLOCKS_PER_SEC);

    if(framesSinceLastDraw++ > 29){
        framesSinceLastDraw = 0;
        screenFPS = to_string((int)fps);
    }

    glLoadIdentity();
    //glRasterPos2f(1.0f, 1.0f); // FPS draws on the lefthand bottom side of the screen now, if anyone knows how to get it to the lefthand top of the screen please fix it ;)
    for(unsigned int i = 0;i < screenFPS.length();i++){
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, screenFPS[i]);
    }
}
<|endoftext|>


<commit_before>/// @file
/// @author  Boris Mikic
/// @version 1.48
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php

#include "Rectangle.h"
#include "Vector2.h"

namespace gtypes
{
	Rectangle::Rectangle() : x(0.0f), y(0.0f), w(0.0f), h(0.0f)
	{
	}

	Rectangle::Rectangle(float x, float y, float w, float h)
	{
		this->x = x;
		this->y = y;
		this->w = w;
		this->h = h;
	}

	Rectangle::Rectangle(Vector2 position, Vector2 size)
	{
		this->x = position.x;
		this->y = position.y;
		this->w = size.x;
		this->h = size.y;
	}

	Rectangle::Rectangle(Vector2 position, float w, float h)
	{
		this->x = position.x;
		this->y = position.y;
		this->w = w;
		this->h = h;
	}

	Rectangle::Rectangle(float x, float y, Vector2 size)
	{
		this->x = x;
		this->y = y;
		this->w = size.x;
		this->h = size.y;
	}

	void Rectangle::set(float x, float y, float w, float h)
	{
		this->x = x;
		this->y = y;
		this->w = w;
		this->h = h;
	}

	void Rectangle::set(Vector2 position, Vector2 size)
	{
		this->x = position.x;
		this->y = position.y;
		this->w = size.x;
		this->h = size.y;
	}

	void Rectangle::set(Vector2 position, float w, float h)
	{
		this->x = position.x;
		this->y = position.y;
		this->w = w;
		this->h = h;
	}

	void Rectangle::set(float x, float y, Vector2 size)
	{
		this->x = x;
		this->y = y;
		this->w = size.x;
		this->h = size.y;
	}

	Vector2 Rectangle::getPosition()
	{
		return Vector2(this->x, this->y);
	}

	void Rectangle::setPosition(Vector2 position)
	{
		this->x = position.x;
		this->y = position.y;
	}

	void Rectangle::setPosition(float x, float y)
	{
		this->x = x;
		this->y = y;
	}

	Vector2 Rectangle::getSize()
	{
		return Vector2(this->w, this->h);
	}

	void Rectangle::setSize(Vector2 size)
	{
		this->w = size.x;
		this->h = size.y;
	}

	void Rectangle::setSize(float w, float h)
	{
		this->w = w;
		this->h = h;
	}

	Vector2 Rectangle::getCenter() const
	{
		return Vector2(this->x + this->w * 0.5f, this->y + this->h * 0.5f);
	}

	float Rectangle::getAspect() const
	{
		return (this->w / this->h);
	}

	Vector2 Rectangle::getTopLeft() const
	{
		return Vector2(this->x, this->y);
	}

	Vector2 Rectangle::getTopRight() const
	{
		return Vector2(this->x + this->w, this->y);
	}

	Vector2 Rectangle::getBottomLeft() const
	{
		return Vector2(this->x, this->y + this->h);
	}

	Vector2 Rectangle::getBottomRight() const
	{
		return Vector2(this->x + this->w, this->y + this->h);
	}

	float Rectangle::left() const
	{
		return this->x;
	}

	float Rectangle::right() const
	{
		return (this->x + this->w);
	}

	float Rectangle::top() const
	{
		return this->y;
	}

	float Rectangle::bottom() const
	{
		return (this->y + this->h);
	}

	float Rectangle::centerX() const
	{
		return (this->x + this->w * 0.5f);
	}

	float Rectangle::centerY() const
	{
		return (this->y + this->h * 0.5f);
	}

	bool Rectangle::intersects(const Rectangle& other) const
	{
		return (this->x + this->w > other.x && this->x < other.x + other.w &&
				this->y + this->h > other.y && this->y < other.y + other.h);
	}

	bool Rectangle::contains(const Rectangle& other) const
	{
		return (this->x <= other.x && this->x + this->w >= other.x + other.w &&
			this->y <= other.y && this->y + this->h >= other.y + other.h);
	}

	bool Rectangle::isPointInside(const Vector2& vector) const
	{
		return (vector.x >= this->x && vector.y >= this->y && vector.x < this->x + this->w && vector.y < this->y + this->h);
	}

	bool Rectangle::isPointInside(float x, float y) const
	{
		return (x >= this->x && y >= this->y && x < this->x + this->w && y < this->y + this->h);
	}

	Rectangle Rectangle::operator+(Vector2 vector) const
	{
		Rectangle result(*this);
		result.x += vector.x;
		result.y += vector.y;
		return result;
	}

	Rectangle Rectangle::operator-(Vector2 vector) const
	{
		Rectangle result(*this);
		result.x -= vector.x;
		result.y -= vector.y;
		return result;
	}

	Rectangle Rectangle::operator*(Vector2 vector) const
	{
		Rectangle result(*this);
		result.w *= vector.x;
		result.h *= vector.y;
		return result;
	}

	Rectangle Rectangle::operator/(Vector2 vector) const
	{
		Rectangle result(*this);
		result.w /= vector.x;
		result.h /= vector.y;
		return result;
	}

	Rectangle Rectangle::operator*(float scale) const
	{
		Rectangle result(*this);
		result.w *= scale;
		result.h *= scale;
		return result;
	}

	Rectangle Rectangle::operator/(float scale) const
	{
		Rectangle result(*this);
		result.w /= scale;
		result.h /= scale;
		return result;
	}

	Rectangle Rectangle::operator+=(const Vector2& vector)
	{
		this->x += vector.x;
		this->y += vector.y;
		return (*this);
	}

	Rectangle Rectangle::operator-=(const Vector2& vector)
	{
		this->x -= vector.x;
		this->y -= vector.y;
		return (*this);
	}

	Rectangle Rectangle::operator*=(const Vector2& vector)
	{
		this->w *= vector.x;
		this->h *= vector.y;
		return (*this);
	}

	Rectangle Rectangle::operator/=(const Vector2& vector)
	{
		this->w /= vector.x;
		this->h /= vector.y;
		return (*this);
	}

	Rectangle Rectangle::operator*=(float scale)
	{
		this->w *= scale;
		this->h *= scale;
		return (*this);
	}

	Rectangle Rectangle::operator/=(float scale)
	{
		this->w /= scale;
		this->h /= scale;
		return (*this);
	}

	bool Rectangle::operator==(const Rectangle& other) const
	{
		return (this->x == other.x && this->y == other.y && this->w == other.w && this->h == other.h);
	}

	bool Rectangle::operator!=(const Rectangle& other) const
	{
		return !(*this == other);
	}

}

<commit_msg><commit_after>/// @file
/// @author  Boris Mikic
/// @version 1.48
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php

#pragma message("WARNING! This version of the library is deprecated! Please use the one from: http://libgtypes.googlecode.com")

#include "Rectangle.h"
#include "Vector2.h"

namespace gtypes
{
	Rectangle::Rectangle() : x(0.0f), y(0.0f), w(0.0f), h(0.0f)
	{
	}

	Rectangle::Rectangle(float x, float y, float w, float h)
	{
		this->x = x;
		this->y = y;
		this->w = w;
		this->h = h;
	}

	Rectangle::Rectangle(Vector2 position, Vector2 size)
	{
		this->x = position.x;
		this->y = position.y;
		this->w = size.x;
		this->h = size.y;
	}

	Rectangle::Rectangle(Vector2 position, float w, float h)
	{
		this->x = position.x;
		this->y = position.y;
		this->w = w;
		this->h = h;
	}

	Rectangle::Rectangle(float x, float y, Vector2 size)
	{
		this->x = x;
		this->y = y;
		this->w = size.x;
		this->h = size.y;
	}

	void Rectangle::set(float x, float y, float w, float h)
	{
		this->x = x;
		this->y = y;
		this->w = w;
		this->h = h;
	}

	void Rectangle::set(Vector2 position, Vector2 size)
	{
		this->x = position.x;
		this->y = position.y;
		this->w = size.x;
		this->h = size.y;
	}

	void Rectangle::set(Vector2 position, float w, float h)
	{
		this->x = position.x;
		this->y = position.y;
		this->w = w;
		this->h = h;
	}

	void Rectangle::set(float x, float y, Vector2 size)
	{
		this->x = x;
		this->y = y;
		this->w = size.x;
		this->h = size.y;
	}

	Vector2 Rectangle::getPosition()
	{
		return Vector2(this->x, this->y);
	}

	void Rectangle::setPosition(Vector2 position)
	{
		this->x = position.x;
		this->y = position.y;
	}

	void Rectangle::setPosition(float x, float y)
	{
		this->x = x;
		this->y = y;
	}

	Vector2 Rectangle::getSize()
	{
		return Vector2(this->w, this->h);
	}

	void Rectangle::setSize(Vector2 size)
	{
		this->w = size.x;
		this->h = size.y;
	}

	void Rectangle::setSize(float w, float h)
	{
		this->w = w;
		this->h = h;
	}

	Vector2 Rectangle::getCenter() const
	{
		return Vector2(this->x + this->w * 0.5f, this->y + this->h * 0.5f);
	}

	float Rectangle::getAspect() const
	{
		return (this->w / this->h);
	}

	Vector2 Rectangle::getTopLeft() const
	{
		return Vector2(this->x, this->y);
	}

	Vector2 Rectangle::getTopRight() const
	{
		return Vector2(this->x + this->w, this->y);
	}

	Vector2 Rectangle::getBottomLeft() const
	{
		return Vector2(this->x, this->y + this->h);
	}

	Vector2 Rectangle::getBottomRight() const
	{
		return Vector2(this->x + this->w, this->y + this->h);
	}

	float Rectangle::left() const
	{
		return this->x;
	}

	float Rectangle::right() const
	{
		return (this->x + this->w);
	}

	float Rectangle::top() const
	{
		return this->y;
	}

	float Rectangle::bottom() const
	{
		return (this->y + this->h);
	}

	float Rectangle::centerX() const
	{
		return (this->x + this->w * 0.5f);
	}

	float Rectangle::centerY() const
	{
		return (this->y + this->h * 0.5f);
	}

	bool Rectangle::intersects(const Rectangle& other) const
	{
		return (this->x + this->w > other.x && this->x < other.x + other.w &&
				this->y + this->h > other.y && this->y < other.y + other.h);
	}

	bool Rectangle::contains(const Rectangle& other) const
	{
		return (this->x <= other.x && this->x + this->w >= other.x + other.w &&
			this->y <= other.y && this->y + this->h >= other.y + other.h);
	}

	bool Rectangle::isPointInside(const Vector2& vector) const
	{
		return (vector.x >= this->x && vector.y >= this->y && vector.x < this->x + this->w && vector.y < this->y + this->h);
	}

	bool Rectangle::isPointInside(float x, float y) const
	{
		return (x >= this->x && y >= this->y && x < this->x + this->w && y < this->y + this->h);
	}

	Rectangle Rectangle::operator+(Vector2 vector) const
	{
		Rectangle result(*this);
		result.x += vector.x;
		result.y += vector.y;
		return result;
	}

	Rectangle Rectangle::operator-(Vector2 vector) const
	{
		Rectangle result(*this);
		result.x -= vector.x;
		result.y -= vector.y;
		return result;
	}

	Rectangle Rectangle::operator*(Vector2 vector) const
	{
		Rectangle result(*this);
		result.w *= vector.x;
		result.h *= vector.y;
		return result;
	}

	Rectangle Rectangle::operator/(Vector2 vector) const
	{
		Rectangle result(*this);
		result.w /= vector.x;
		result.h /= vector.y;
		return result;
	}

	Rectangle Rectangle::operator*(float scale) const
	{
		Rectangle result(*this);
		result.w *= scale;
		result.h *= scale;
		return result;
	}

	Rectangle Rectangle::operator/(float scale) const
	{
		Rectangle result(*this);
		result.w /= scale;
		result.h /= scale;
		return result;
	}

	Rectangle Rectangle::operator+=(const Vector2& vector)
	{
		this->x += vector.x;
		this->y += vector.y;
		return (*this);
	}

	Rectangle Rectangle::operator-=(const Vector2& vector)
	{
		this->x -= vector.x;
		this->y -= vector.y;
		return (*this);
	}

	Rectangle Rectangle::operator*=(const Vector2& vector)
	{
		this->w *= vector.x;
		this->h *= vector.y;
		return (*this);
	}

	Rectangle Rectangle::operator/=(const Vector2& vector)
	{
		this->w /= vector.x;
		this->h /= vector.y;
		return (*this);
	}

	Rectangle Rectangle::operator*=(float scale)
	{
		this->w *= scale;
		this->h *= scale;
		return (*this);
	}

	Rectangle Rectangle::operator/=(float scale)
	{
		this->w /= scale;
		this->h /= scale;
		return (*this);
	}

	bool Rectangle::operator==(const Rectangle& other) const
	{
		return (this->x == other.x && this->y == other.y && this->w == other.w && this->h == other.h);
	}

	bool Rectangle::operator!=(const Rectangle& other) const
	{
		return !(*this == other);
	}

}

<|endoftext|>


<commit_before>#include "scanner.h"

namespace flora {

// Public Methods

Scanner::Scanner() {
  // TODO
}

void Scanner::Initialize() {
  UNIMPLEMENTED();
}

Token Scanner::Advance() {
  switch (state_) {
  case Scanner::State::Uninitialized:
    ReportScannerError("the scanner is uninitialized");
    return Token::Illegal;

  case Scanner::State::Running:
    return Scan();

  case Scanner::State::Recording: {
    Token token = Scan();
    records_.push(std::make_pair(token, literal_));
    return token;
  }

  case Scanner::State::Restoring: {
    // Sequeeze the first recorded token
    std::pair<Token, std::string> &token = records_.front();
    records_.pop();
    // Check if no more recorded tokens
    if (records_.empty())
      state_ = Scanner::State::Running;
    SetTokenLiteral(token.second);
    return token.first;
  }

  case Scanner::State::End:
    return Token::EndOfSource;

  case Scanner::State::Error:
    return Token::Illegal;
  }
  UNREACHABLE();
}

void Scanner::SaveBookmark() {
  // Clean the recording queue
  while (!records_.empty())
    records_.pop();
  // Set state to recording
  state_ = Scanner::State::Recording;
}

void Scanner::LoadBookmark() {
  // Set state to restoring
  state_ = Scanner::State::Restoring;
}

void Scanner::ClearBookmark() {
  // Clean the recording queue
  while (!records_.empty())
    records_.pop();
  // Set state to running
  state_ = Scanner::State::Running;
}

// Private methods

char Scanner::Next() {
  // TODO
}

bool Scanner::Match(char expected) {
  // TODO
}

void Scanner::SetTokenLiteral(const char *literal) {
  literal_.assign(literal);
}

void Scanner::SetTokenLiteral(std::string &literal) {
  literal_ = std::move(literal);
}

void Scanner::SetTokenLiteral(char literal) {
  literal_.clear();
  literal_.push_back(literal);
}

void Scanner::ClearTokenLiteral() {
  literal_.clear();
}

void Scanner::ReportScannerError(const char *message) {
  state_ = Scanner::State::Error;
  SetTokenLiteral(message);
}

void Scanner::MarkEndOfSource() {
  state_ = Scanner::State::End;
}

Token Scanner::Scan() {
  ClearTokenLiteral();
  char ch;
  while (true) {
    switch (ch = Next()) {
    case character::EOS:
      MarkEndOfSource();
      return Token::EndOfSource;
    case '\n':
    case ' ':
    case '\t':
      continue;
    case '(': return Token::LeftParenthesis;
    case ')': return Token::RightParenthesis;
    case '[': return Token::LeftBracket;
    case ']': return Token::RightBracket;
    case '{': return Token::LeftBrace;
    case '}': return Token::RightBrace;
    case ':': return Token::Colon;
    case ';': return Token::Semicolon;
    case '~': return Token::BitwiseNot;
    case '?': return Token::Conditional;
    case ',': return Token::Comma;
    case '.': // . ...
      if (Match('.')) {
        if (Match('.')) {
          return Token::Ellipsis;
        } else {
          ReportScannerError("illegal token");
          return Token::Illegal;
        }
      }
      return Token::Period;
    case '&': // & && &=
      if (Match('&')) {
        return Token::LogicalAnd;
      } else if (Match('=')) {
        return Token::AssignmentBitwiseAnd;
      } else {
        return Token::BitwiseAnd;
      }
    case '|': // | || |=
      if (Match('|')) {
        return Token::LogicalOr;
      } else if (Match('=')) {
        return Token::AssignmentBitwiseOr;
      } else {
        return Token::BitwiseOr;
      }
    case '^': // ^ ^=
      return Match('=') ? Token::AssignmentBitwiseXor : Token::BitwiseXor;
    case '<': // < << <= <<=
      if (Match('<')) {
        return Match('=') ? Token::AssignmentShiftLeft : Token::ShiftLeft;
      } else if (Match('=')) {
        return Token::LessThanOrEqual;
      } else {
        return Token::LessThan;
      }
    case '>': // > >> >= >>=
      if (Match('>')) {
        return Match('=') ? Token::AssignmentShiftRight : Token::ShiftRight;
      } else if (Match('=')) {
        return Token::GreaterThanOrEqual;
      } else {
        return Token::GreaterThan;
      }
    case '!': // ! !=
      return Match('=') ? Token::NotEqual : Token::LogicalNot;
    case '=': // = == =>
      if (Match('>')) {
        return Token::Arrow;
      } else if (Match('=')) {
        return Token::Equal;
      } else {
        return Token::Assignment;
      }
    case '+': // + ++ +=
      if (Match('+')) {
        return Token::Increment;
      } else if (Match('=')) {
        return Token::AssignmentAddition;
      } else {
        return Token::Addition;
      }
    case '-': // - -- -=
      if (Match('-')) {
        return Token::Decrement;
      } else if (Match('=')) {
        return Token::AssignmentSubtraction;
      } else {
        return Token::Subtraction;
      }
    case '*': // * *=
      return Match('=') ? Token::AssignmentMultiplication:Token::Multiplication;
    case '/': // / /= /* multiple line comment */ // single line comment
      if (Match('=')) {
        return Token::AssignmentDivision;
      } else if (Match('*')) {
        SkipMultipleLineComment();
      } else if (Match('/')) {
        SkipSingleLineComment();
      } else {
        return Token::Division;
      }
      continue;
    case '%': // % %=
      return Match('=') ? Token::AssignmentModulus : Token::Modulus;
    case '"': // string literal
      return ScanStringLiteral();
    case '\'': // character literal
      return ScanCharacterLiteral();
    default:
      if (character::IsIdentifierStart(ch)) {
        return ScanIdentifierOrKeyword(ch);
      } else if (character::IsDecimalDigit(ch)) {
        return ScanIntegerOrRealNumber(ch);
      } else {
        ReportScannerError("unknown token");
        return Token::Illegal;
      }
    }
  }
}

bool Scanner::SkipMultipleLineComment() {
  int cascade = 1;
  char ch;
  while (true) {
    ch = Next();
    if (ch == '/') {
      if (peek == '*') {
        Next();
        cascade++;
      }
    } else if (ch == '*') {
      if (peek == '/') {
        Next();
        cascade--;
        if (cascade == 0) break;
      }
    } else if (ch == character::EOS) {
      ReportScannerError("unexpected end of source in multiple line comment");
      return false;
    }
  }
  return true;
}

void Scanner::SkipSingleLineComment() {
  while (!character::IsLineFeed(peek) && peek != character::EOS)
    Next();
}

Token Scanner::ScanStringLiteral() {
  std::string literal;
  char ch;
  while (true) {
    ch = Next();
    if (ch == character::EOS) {
      ReportScannerError("unexpected EOF in string literal");
      return Token::Illegal;
    } else if (ch == '\\') {
      literal.push_back(ScanStringEscape());
    } else if (ch == '"') {
      break;
    } else {
      literal.push_back(ch);
    }
  }
  SetTokenLiteral(literal);
  return Token::String;
}

Token Scanner::ScanCharacterLiteral() {
  char literal = Next();
  if (literal == character::EOS) {
    ReportScannerError("unexpected EOF in character literal");
    return Token::Illegal;
  } else if (literal == '\\') {
    literal = ScanCharacterEscape();
  }
  // to ensure that there is only one character in literal
  if (Next() != '\'') {
    ReportScannerError("too more character in literal");
    return Token::Illegal;
  }
  SetTokenLiteral(literal);
  return Token::Character;
}

Token Scanner::ScanIdentifierOrKeyword(char firstChar) {
  std::string identifier;
  identifier.push_back(firstChar);

  while (character::IsIdentifierBody(peek)) {
    identifier.push_back(Next());
  }
  Token token = Tokens::LookupKeyword(identifier);
  if (token != Token::Identifier) SetTokenLiteral(identifier);
  return token;
}

Token Scanner::ScanIntegerOrRealNumber(char firstChar) {
  // There are 4 kinds of integer:
  // (1) Hexidecimal integer
  // (2) Decimal integer
  // (3) Octal integer
  // (4) Binary integer
  // (1), (3) and (4) has a prefix, so we can easily dintinguish them
  std::string num;
  if (firstChar == '0') {
    if (peek == 'x') {
      Next();
      return ScanHexInteger();
    } else if (peek == 'o') {
      Next();
      return ScanOctalInteger();
    } else if (peek == 'b') {
      Next();
      return ScanBinaryInteger();
    }
  }
  num.push_back(firstChar);
  // Scan the integral part
  while (IsDecimalDigit(peek)) {
    num.push_back(firstChar);
  }
  // Real number
  if (peek == '.' || AsciiToLowerCase(peek) == 'e') {
    return ScanRealNumber(&num);
  }
  // Integer
  SetTokenLiteral(num);
  return Token::Integer;
}

Token Scanner::ScanRealNumber(const std::string *integral_part,
                              bool scanned_period) {
  std::string num;
  if (integral_part) {
    num = *integral_part;
  } else {
    num.push_back('0');
  }
  // Fraction part
  if (Match('.')) {
    while (IsDecimalDigit(peek)) {
      num.push_back(firstChar);
    }
  }
  // Exponent part
  if (peek == 'E' || peek == 'e') {
    num.push_back(Next());
    if (peek == '+' || peek == '-')
      num.push_back(Next());
    // An error circumstance: 1.234E
    if (!IsDecimalDigit(peek)) {
      ReportScannerError("unexpected end of source in real number literal");
      return Token::Illegal();
    }
    while (IsDecimalDigit(peek)) {
      num.push_back(firstChar);
    }
  }
  SetTokenLiteral(num);
  return Token::RealNumber;
}

#define SCAN_INTEGER(base, ch, checker)\
  Token Scanner::Scan##base##Integer() {\
    std::string num;\
    num.push_back(ch);\
    if (!checker(peek)) {\
      ReportScannerError("unexpected end of source in integer literal");\
      return Token::Illegal();\
    }\
    while (checker(peek))\
      num.push_back(Next());\
    SetTokenLiteral(num);\
    return Token::Integer;\
  }

SCAN_INTEGER(Hex, 'x', IsHexDigit)
SCAN_INTEGER(Octal, 'o', IsOctalDigit)
SCAN_INTEGER(Binary, 'b', IsBinaryDigit)

}<commit_msg>Fixed syntax errors.<commit_after>#include "scanner.h"

namespace flora {

// Public Methods

Scanner::Scanner() {
  // TODO
}

void Scanner::Initialize() {
  UNIMPLEMENTED();
}

Token Scanner::Advance() {
  switch (state_) {
  case Scanner::State::Uninitialized:
    ReportScannerError("the scanner is uninitialized");
    return Token::Illegal;

  case Scanner::State::Running:
    return Scan();

  case Scanner::State::Recording: {
    Token token = Scan();
    records_.push(std::make_pair(token, literal_));
    return token;
  }

  case Scanner::State::Restoring: {
    // Sequeeze the first recorded token
    std::pair<Token, std::string> &token = records_.front();
    records_.pop();
    // Check if no more recorded tokens
    if (records_.empty())
      state_ = Scanner::State::Running;
    SetTokenLiteral(token.second);
    return token.first;
  }

  case Scanner::State::End:
    return Token::EndOfSource;

  case Scanner::State::Error:
    return Token::Illegal;
  }
  UNREACHABLE();
}

void Scanner::SaveBookmark() {
  // Clean the recording queue
  while (!records_.empty())
    records_.pop();
  // Set state to recording
  state_ = Scanner::State::Recording;
}

void Scanner::LoadBookmark() {
  // Set state to restoring
  state_ = Scanner::State::Restoring;
}

void Scanner::ClearBookmark() {
  // Clean the recording queue
  while (!records_.empty())
    records_.pop();
  // Set state to running
  state_ = Scanner::State::Running;
}

// Private methods

char Scanner::Next() {
  // TODO
  UNIMPLEMENTED();
}

bool Scanner::Match(char expected) {
  // TODO
  UNIMPLEMENTED();
}

void Scanner::SetTokenLiteral(const char *literal) {
  literal_.assign(literal);
}

void Scanner::SetTokenLiteral(std::string &literal) {
  literal_ = std::move(literal);
}

void Scanner::SetTokenLiteral(char literal) {
  literal_.clear();
  literal_.push_back(literal);
}

void Scanner::ClearTokenLiteral() {
  literal_.clear();
}

void Scanner::ReportScannerError(const char *message) {
  state_ = Scanner::State::Error;
  SetTokenLiteral(message);
}

void Scanner::MarkEndOfSource() {
  state_ = Scanner::State::End;
}

Token Scanner::Scan() {
  ClearTokenLiteral();
  char ch;
  while (true) {
    switch (ch = Next()) {
    case character::EOS:
      MarkEndOfSource();
      return Token::EndOfSource;
    case '\n':
    case ' ':
    case '\t':
      continue;
    case '(': return Token::LeftParenthesis;
    case ')': return Token::RightParenthesis;
    case '[': return Token::LeftBracket;
    case ']': return Token::RightBracket;
    case '{': return Token::LeftBrace;
    case '}': return Token::RightBrace;
    case ':': return Token::Colon;
    case ';': return Token::Semicolon;
    case '~': return Token::BitwiseNot;
    case '?': return Token::Conditional;
    case ',': return Token::Comma;
    case '.': // . ...
      if (Match('.')) {
        if (Match('.')) {
          return Token::Ellipsis;
        } else {
          ReportScannerError("illegal token");
          return Token::Illegal;
        }
      }
      return Token::Period;
    case '&': // & && &=
      if (Match('&')) {
        return Token::LogicalAnd;
      } else if (Match('=')) {
        return Token::AssignmentBitwiseAnd;
      } else {
        return Token::BitwiseAnd;
      }
    case '|': // | || |=
      if (Match('|')) {
        return Token::LogicalOr;
      } else if (Match('=')) {
        return Token::AssignmentBitwiseOr;
      } else {
        return Token::BitwiseOr;
      }
    case '^': // ^ ^=
      return Match('=') ? Token::AssignmentBitwiseXor : Token::BitwiseXor;
    case '<': // < << <= <<=
      if (Match('<')) {
        return Match('=') ? Token::AssignmentShiftLeft : Token::ShiftLeft;
      } else if (Match('=')) {
        return Token::LessThanOrEqual;
      } else {
        return Token::LessThan;
      }
    case '>': // > >> >= >>=
      if (Match('>')) {
        return Match('=') ? Token::AssignmentShiftRight : Token::ShiftRight;
      } else if (Match('=')) {
        return Token::GreaterThanOrEqual;
      } else {
        return Token::GreaterThan;
      }
    case '!': // ! !=
      return Match('=') ? Token::NotEqual : Token::LogicalNot;
    case '=': // = == =>
      if (Match('>')) {
        return Token::Arrow;
      } else if (Match('=')) {
        return Token::Equal;
      } else {
        return Token::Assignment;
      }
    case '+': // + ++ +=
      if (Match('+')) {
        return Token::Increment;
      } else if (Match('=')) {
        return Token::AssignmentAddition;
      } else {
        return Token::Addition;
      }
    case '-': // - -- -=
      if (Match('-')) {
        return Token::Decrement;
      } else if (Match('=')) {
        return Token::AssignmentSubtraction;
      } else {
        return Token::Subtraction;
      }
    case '*': // * *=
      return Match('=') ? Token::AssignmentMultiplication:Token::Multiplication;
    case '/': // / /= /* multiple line comment */ // single line comment
      if (Match('=')) {
        return Token::AssignmentDivision;
      } else if (Match('*')) {
        SkipMultipleLineComment();
      } else if (Match('/')) {
        SkipSingleLineComment();
      } else {
        return Token::Division;
      }
      continue;
    case '%': // % %=
      return Match('=') ? Token::AssignmentModulus : Token::Modulus;
    case '"': // string literal
      return ScanStringLiteral();
    case '\'': // character literal
      return ScanCharacterLiteral();
    default:
      if (character::IsIdentifierStart(ch)) {
        return ScanIdentifierOrKeyword(ch);
      } else if (character::IsDecimalDigit(ch)) {
        return ScanIntegerOrRealNumber(ch);
      } else {
        ReportScannerError("unknown token");
        return Token::Illegal;
      }
    }
  }
}

bool Scanner::SkipMultipleLineComment() {
  int cascade = 1;
  char ch;
  while (true) {
    ch = Next();
    if (ch == '/') {
      if (peek == '*') {
        Next();
        cascade++;
      }
    } else if (ch == '*') {
      if (peek == '/') {
        Next();
        cascade--;
        if (cascade == 0) break;
      }
    } else if (ch == character::EOS) {
      ReportScannerError("unexpected end of source in multiple line comment");
      return false;
    }
  }
  return true;
}

void Scanner::SkipSingleLineComment() {
  while (!character::IsLineFeed(peek) && peek != character::EOS)
    Next();
}

Token Scanner::ScanStringLiteral() {
  std::string literal;
  char ch;
  while (true) {
    ch = Next();
    if (ch == character::EOS) {
      ReportScannerError("unexpected EOF in string literal");
      return Token::Illegal;
    } else if (ch == '\\') {
      literal.push_back(ScanStringEscape());
    } else if (ch == '"') {
      break;
    } else {
      literal.push_back(ch);
    }
  }
  SetTokenLiteral(literal);
  return Token::String;
}

Token Scanner::ScanCharacterLiteral() {
  char literal = Next();
  if (literal == character::EOS) {
    ReportScannerError("unexpected EOF in character literal");
    return Token::Illegal;
  } else if (literal == '\\') {
    literal = ScanCharacterEscape();
  }
  // to ensure that there is only one character in literal
  if (Next() != '\'') {
    ReportScannerError("too more character in literal");
    return Token::Illegal;
  }
  SetTokenLiteral(literal);
  return Token::Character;
}

Token Scanner::ScanIdentifierOrKeyword(char firstChar) {
  std::string identifier;
  identifier.push_back(firstChar);

  while (character::IsIdentifierBody(peek)) {
    identifier.push_back(Next());
  }
  Token token = Tokens::LookupKeyword(identifier);
  if (token != Token::Identifier) SetTokenLiteral(identifier);
  return token;
}

Token Scanner::ScanIntegerOrRealNumber(char firstChar) {
  // There are 4 kinds of integer:
  // (1) Hexidecimal integer
  // (2) Decimal integer
  // (3) Octal integer
  // (4) Binary integer
  // (1), (3) and (4) has a prefix, so we can easily dintinguish them
  std::string num;
  if (firstChar == '0') {
    if (peek == 'x') {
      Next();
      return ScanHexInteger();
    } else if (peek == 'o') {
      Next();
      return ScanOctalInteger();
    } else if (peek == 'b') {
      Next();
      return ScanBinaryInteger();
    }
  }
  num.push_back(firstChar);
  // Scan the integral part
  while (character::IsDecimalDigit(peek)) {
    num.push_back(firstChar);
  }
  // Real number
  if (peek == '.' || character::AsciiToLowerCase(peek) == 'e') {
    return ScanRealNumber(&num);
  }
  // Integer
  SetTokenLiteral(num);
  return Token::Integer;
}

Token Scanner::ScanRealNumber(const std::string *integral_part,
                              bool scanned_period) {
  std::string num;
  if (integral_part) {
    num = *integral_part;
  } else {
    num.push_back('0');
  }
  // Fraction part
  if (Match('.')) {
    while (character::IsDecimalDigit(peek)) {
      num.push_back(Next());
    }
  }
  // Exponent part
  if (peek == 'E' || peek == 'e') {
    num.push_back(Next());
    if (peek == '+' || peek == '-')
      num.push_back(Next());
    // An error circumstance: 1.234E
    if (!character::IsDecimalDigit(peek)) {
      ReportScannerError("unexpected end of source in real number literal");
      return Token::Illegal;
    }
    while (character::IsDecimalDigit(peek)) {
      num.push_back(Next());
    }
  }
  SetTokenLiteral(num);
  return Token::RealNumber;
}

#define SCAN_INTEGER(base, ch, checker)\
  Token Scanner::Scan##base##Integer() {\
    std::string num;\
    num.push_back(ch);\
    if (!checker(peek)) {\
      ReportScannerError("unexpected end of source in integer literal");\
      return Token::Illegal;\
    }\
    while (checker(peek))\
      num.push_back(Next());\
    SetTokenLiteral(num);\
    return Token::Integer;\
  }

SCAN_INTEGER(Hex, 'x', character::IsHexDigit)
SCAN_INTEGER(Octal, 'o', character::IsOctalDigit)
SCAN_INTEGER(Binary, 'b', character::IsBinaryDigit)

}<|endoftext|>


<commit_before>/* ux++ - ux implementation for C++ */

/* LICENSE - The MIT License (MIT)

Copyright (c) 2013 Tomona Nanase

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <cfloat>
#include <cassert>
#include "common.hpp"
#include "Envelope.hpp"

namespace uxpp {

  // <editor-fold desc="-- Construnctors --">

  Envelope::Envelope(float samplingRate) : samplingRate(samplingRate) {
    assert(samplingRate > 0.0f);

    this->reset();
  }
  // </editor-fold>

  // <editor-fold desc="-- Methods --">

  EnvelopeState::values Envelope::getState() const {
    return this->state;
  }

  void Envelope::reset() {
    this->attackTime = (int) (0.05f * this->samplingRate);
    this->peakTime = (int) (0.0f * this->samplingRate);
    this->decayTime = (int) (0.0f * this->samplingRate);
    this->sustainLevel = 1.0f;
    this->releaseTime = (int) (0.05f * this->samplingRate);
    this->state = EnvelopeState::silence;
  }

  void Envelope::attack() {
    this->state = EnvelopeState::attack;

    // precalc
    this->t2 = this->attackTime + this->peakTime;
    this->t3 = this->t2 + this->decayTime;
    this->da = 1.0f / this->attackTime;
    this->dd = (1.0f - this->sustainLevel) / this->decayTime;
  }

  void Envelope::relase(int32_t time) {
    assert(time >= 0);

    if (this->state == EnvelopeState::attack) {
      this->state = EnvelopeState::release;
      this->releaseStartTime = time;

      // precalc
      this->t5 = time + this->releaseTime;
      this->dr = this->sustainLevel / this->releaseTime;
    }
  }

  void Envelope::silence() {
    this->state = EnvelopeState::silence;
  }

  void Envelope::generate(int32_t time, float envelopes[], int32_t count) {
    assert(time >= 0);
    assert(count > 0);
    assert(envelopes != nullptr);

    float res;
    for (int i = 0; i < count; i++, time++) {
      if (this->state == EnvelopeState::attack) {
        res = (time < this->attackTime) ? time * this->da :
                (time < this->t2) ? 1.0f :
                (time < this->t3) ? 1.0f - (time - this->t2) * this->dd :
                this->sustainLevel;
      } else if (this->state == EnvelopeState::release) {
        if (time < this->t5)
          res = this->sustainLevel - (time - this->releaseStartTime) * this->dr;
        else {
          res = 0.0f;
          this->state = EnvelopeState::silence;
        }
      } else
        res = 0.0f;

      envelopes[i] = res;
    }
  }

  void Envelope::setParameter(int32_t data1, float data2) {
    switch ((EnvelopeOperate::values) data1) {
      case EnvelopeOperate::attack:
        assert(data2 >= 0.0f);
        this->attackTime =
                (int) (clamp(data2, FLT_MAX, 0.0f) * this->samplingRate);
        break;

      case EnvelopeOperate::peak:
        assert(data2 >= 0.0f);
        this->peakTime =
                (int) (clamp(data2, FLT_MAX, 0.0f) * this->samplingRate);
        break;

      case EnvelopeOperate::decay:
        assert(data2 >= 0.0f);
        this->decayTime =
                (int) (clamp(data2, FLT_MAX, 0.0f) * this->samplingRate);
        break;

      case EnvelopeOperate::sustain:
        assert(data2 >= 0.0f && data2 <= 1.0f);
        this->sustainLevel = clamp(data2, 1.0f, 0.0f);
        break;

      case EnvelopeOperate::release:
        assert(data2 >= 0.0f);
        this->releaseTime =
                (int) (clamp(data2, FLT_MAX, 0.0f) * this->samplingRate);
        break;

      default:
        break;
    }
  }
  // </editor-fold>
}<commit_msg>Envelope::createConstant関数を実装<commit_after>/* ux++ - ux implementation for C++ */

/* LICENSE - The MIT License (MIT)

Copyright (c) 2013 Tomona Nanase

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <cfloat>
#include <cassert>
#include "common.hpp"
#include "Envelope.hpp"

namespace uxpp {

  // <editor-fold desc="-- Construnctors --">

  Envelope::Envelope(float samplingRate) : samplingRate(samplingRate) {
    assert(samplingRate > 0.0f);

    this->reset();
  }
  // </editor-fold>

  // <editor-fold desc="-- Methods --">

  EnvelopeState::values Envelope::getState() const {
    return this->state;
  }

  void Envelope::reset() {
    this->attackTime = (int) (0.05f * this->samplingRate);
    this->peakTime = (int) (0.0f * this->samplingRate);
    this->decayTime = (int) (0.0f * this->samplingRate);
    this->sustainLevel = 1.0f;
    this->releaseTime = (int) (0.05f * this->samplingRate);
    this->state = EnvelopeState::silence;
  }

  void Envelope::attack() {
    this->state = EnvelopeState::attack;

    // precalc
    this->t2 = this->attackTime + this->peakTime;
    this->t3 = this->t2 + this->decayTime;
    this->da = 1.0f / this->attackTime;
    this->dd = (1.0f - this->sustainLevel) / this->decayTime;
  }

  void Envelope::relase(int32_t time) {
    assert(time >= 0);

    if (this->state == EnvelopeState::attack) {
      this->state = EnvelopeState::release;
      this->releaseStartTime = time;

      // precalc
      this->t5 = time + this->releaseTime;
      this->dr = this->sustainLevel / this->releaseTime;
    }
  }

  void Envelope::silence() {
    this->state = EnvelopeState::silence;
  }

  void Envelope::generate(int32_t time, float envelopes[], int32_t count) {
    assert(time >= 0);
    assert(count > 0);
    assert(envelopes != nullptr);

    float res;
    for (int i = 0; i < count; i++, time++) {
      if (this->state == EnvelopeState::attack) {
        res = (time < this->attackTime) ? time * this->da :
                (time < this->t2) ? 1.0f :
                (time < this->t3) ? 1.0f - (time - this->t2) * this->dd :
                this->sustainLevel;
      } else if (this->state == EnvelopeState::release) {
        if (time < this->t5)
          res = this->sustainLevel - (time - this->releaseStartTime) * this->dr;
        else {
          res = 0.0f;
          this->state = EnvelopeState::silence;
        }
      } else
        res = 0.0f;

      envelopes[i] = res;
    }
  }

  void Envelope::setParameter(int32_t data1, float data2) {
    switch ((EnvelopeOperate::values) data1) {
      case EnvelopeOperate::attack:
        assert(data2 >= 0.0f);
        this->attackTime =
                (int) (clamp(data2, FLT_MAX, 0.0f) * this->samplingRate);
        break;

      case EnvelopeOperate::peak:
        assert(data2 >= 0.0f);
        this->peakTime =
                (int) (clamp(data2, FLT_MAX, 0.0f) * this->samplingRate);
        break;

      case EnvelopeOperate::decay:
        assert(data2 >= 0.0f);
        this->decayTime =
                (int) (clamp(data2, FLT_MAX, 0.0f) * this->samplingRate);
        break;

      case EnvelopeOperate::sustain:
        assert(data2 >= 0.0f && data2 <= 1.0f);
        this->sustainLevel = clamp(data2, 1.0f, 0.0f);
        break;

      case EnvelopeOperate::release:
        assert(data2 >= 0.0f);
        this->releaseTime =
                (int) (clamp(data2, FLT_MAX, 0.0f) * this->samplingRate);
        break;

      default:
        break;
    }
  }
  // </editor-fold>

  // <editor-fold desc="-- Static Methods --">

  void Envelope::createConstant(Envelope& envelope) {
    envelope.reset();
    envelope.attackTime = 0;
    envelope.peakTime = 0;
    envelope.decayTime = 0;
    envelope.sustainLevel = 1.0f;
    envelope.releaseTime = 0;
  }

  Envelope* Envelope::createConstant(float samplingRate) {
    Envelope* envelope = new Envelope(samplingRate);
    envelope->attackTime = 0;
    envelope->peakTime = 0;
    envelope->decayTime = 0;
    envelope->sustainLevel = 1.0f;
    envelope->releaseTime = 0;

    return envelope;
  }
  // </editor-fold>
}<|endoftext|>


<commit_before>#ifndef DUNE_STUFF_FUNCTION_EXPRESSION_HH
#define DUNE_STUFF_FUNCTION_EXPRESSION_HH

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#else
  #include "config.h"
#endif // ifdef HAVE_CMAKE_CONFIG

#include <sstream>
#include <vector>

#if HAVE_EIGEN
  #include <Eigen/Core>
#endif // HAVE_EIGEN

#include <dune/common/fvector.hh>
#include <dune/common/dynvector.hh>
#include <dune/common/exceptions.hh>

#ifdef HAVE_DUNE_FEM
  #include <dune/fem/function/common/function.hh>
  #include <dune/fem/space/common/functionspace.hh>
#endif // HAVE_DUNE_FEM

#include <dune/stuff/common/parameter/tree.hh>
#include <dune/stuff/common/string.hh>

#include "expression/mathexpr.hh"
#include "interface.hh"

namespace Dune {
namespace Stuff {
namespace Function {

/**
  \brief  Provides a function which evaluates a given mathematical expression at runtime.

          Given a mathematical expression as a string, a domain \f$ K_d^{m \geq 1} \f$ and a range \f$ K_r^{n \geq 1}
          \f$ this function represents the map
          \f{eqnarray}
            f:K_d^m \to K_r^n\\
            x = (x_1, \dots, x_m)' \mapsto (f_1(x), \dots f_n(x))',
          \f}
          where \f$ K_d \f$ is the DomainType and \f$ K_r \f$ is the RangeType, usually a power of \f$ \mathcal{R} \f$.
          The name of the variable as well as the \f$ n \f$ expressions of \f$f_1, \dots, f_n\f$ have to be given in a
          Dune::ParameterTree in the following form:
\code variable: x
expression.0: 2*x[0]
expression.1: sin(x[1])*x[0]\endcode
          There have to exist at least \f$n\f$ expressions; the entries of the variable are indexed by \f$[i]\f$ for
          \f$ 0 \leq i \leq m - 1 \f$.
 **/
template< class DomainFieldImp, int maxDimDomain, class RangeFieldImp, int maxDimRange >
class Expression
  : public Interface< DomainFieldImp, maxDimDomain, RangeFieldImp, maxDimRange >
{
public:
  typedef DomainFieldImp DomainFieldType;

  typedef RangeFieldImp RangeFieldType;

  typedef Interface< DomainFieldImp, maxDimDomain, RangeFieldImp, maxDimRange > BaseType;

  typedef Expression< DomainFieldImp, maxDimDomain, RangeFieldImp, maxDimRange > ThisType;

  Expression(const std::string _variable, const std::string _expression)
  {
    const std::vector< std::string > expressions(1, _expression);
    setup(_variable, expressions);
  } // Expression(const std::string variable, const std::string expression)

  Expression(const std::string _variable, const std::vector< std::string > _expressions)
  {
    setup(_variable, _expressions);
  } // Expression(const std::string variable, const std::vector< std::string >& expressions)

  Expression(const ThisType& other)
  {
    setup(other.variable(), other.expression());
  } // Expression(const ThisType& other)

  static ThisType createFromParamTree(const Dune::ParameterTree& paramTree)
  {
    const Dune::Stuff::Common::ExtendedParameterTree extendedParamtree(paramTree);
    // get variable
    const std::string variable = extendedParamtree.get< std::string >("variable");
    // get expressions
    const std::vector< std::string > expressions = extendedParamtree.getVector< std::string >("expression", 1);
    // create and return
    return ThisType(variable, expressions);
  } // static ThisType createFromParamTree(const Stuff::Common::ExtendedParameterTree& paramTree)

  ThisType& operator=(const ThisType& other)
  {
    if (this != &other) {
      cleanup();
      setup(other.variable(), other.expression());
    }
    return this;
  } // ThisType& operator=(const ThisType& other)

  ~Expression()
  {
    cleanup();
  } // ~Expression()

  void report(const std::string name = "stuff.function.expression",
              std::ostream& stream = std::cout,
              const std::string& prefix = "") const
  {
    const std::string tmp = name + "(" + variable() + ") = ";
    stream << prefix << tmp;
    if (expression().size() == 1)
        stream << expression()[0] << std::endl;
    else {
      stream << "[ " << expression()[0] << ";" << std::endl;
      const std::string whitespace = Dune::Stuff::Common::whitespaceify(tmp + "[ ");
      for (unsigned int i = 1; i < expression().size() - 1; ++i)
        stream << prefix << whitespace << expression()[i] << ";" << std::endl;
      stream << prefix << whitespace << expression()[expression().size() -1] << " ]" << std::endl;
    }
  } // void report(const std::string, std::ostream&, const std::string&) const

  std::string variable() const
  {
    return variable_;
  }

  const std::vector< std::string > expression() const
  {
    return expressions_;
  }

  unsigned int dimRange() const
  {
    return std::min(int(actualDimRange_), maxDimRange);
  }

  //! needed for Interface
  virtual void evaluate(const Dune::FieldVector< DomainFieldImp, maxDimDomain >& arg, Dune::FieldVector< RangeFieldImp, maxDimRange >& ret) const
  {
    // ensure right dimensions
    assert(arg.size() <= maxDimDomain);
    assert(ret.size() <= dimRange());
    // arg
    for (typename Dune::FieldVector< DomainFieldImp, maxDimDomain >::size_type i = 0; i < arg.size(); ++i) {
      *(arg_[i]) = arg[i];
    }
    // ret
    for (typename Dune::FieldVector< RangeFieldImp, maxDimRange >::size_type i = 0; i < ret.size(); ++i) {
      ret[i] = op_[i]->Val();
    }
  }

  template< class DomainVectorType, class RangeVectorType >
  void evaluate(const Dune::DenseVector< DomainVectorType >& arg, Dune::DenseVector< RangeVectorType >& ret) const
  {
    // ensure right dimensions
    assert(arg.size() <= maxDimDomain);
    assert(ret.size() <= dimRange());
    // arg
    for (typename Dune::DenseVector< DomainVectorType >::size_type i = 0; i < arg.size(); ++i) {
      *(arg_[i]) = arg[i];
    }
    // ret
    for (typename Dune::DenseVector< RangeVectorType >::size_type i = 0; i < ret.size(); ++i) {
      ret[i] = op_[i]->Val();
    }
  }

#ifdef HAVE_EIGEN
  /**
   * \attention ret is resized to size dimRange()!
   */
  void evaluate(const Eigen::VectorXd& arg, Eigen::VectorXd& ret) const
  {
    // ensure right dimensions
    assert(arg.size() <= maxDimDomain);
    ret.resize(dimRange());
    // arg
    for (int i = 0; i < arg.size(); ++ i) {
      *(arg_[i]) = arg(i);
    }
    // ret
    for (int i = 0; i < ret.size(); ++ i) {
      ret(i) = op_[i]->Val();
    }
  } // void evaluate(const Eigen::VectorXd& arg, Eigen::VectorXd& ret) const
#endif // HAVE_EIGEN

private:
  void setup(const std::string& _variable, const std::vector< std::string >& _expressions)
  {
    assert(maxDimDomain > 0);
    assert(maxDimRange > 0);
    // set expressions
    if (_expressions.size() < 1)
      DUNE_THROW(Dune::InvalidStateException,"\nError: Given 'expressions'-vector is empty!");
    actualDimRange_ = std::min(int(_expressions.size()), maxDimRange);
    expressions_ = _expressions;
    // set variable (i.e. "x")
    variable_ = _variable;
    // fill variables (i.e. "x[0]", "x[1]", ...)
    for (int i = 0; i < maxDimDomain; ++i) {
      std::stringstream variableStream;
      variableStream << variable_ << "[" << i << "]";
      variables_.push_back(variableStream.str());
    }
    // create epressions
    for (unsigned int i = 0; i < maxDimDomain; ++i) {
      arg_[i] = new DomainFieldType(0.0);
      var_arg_[i] = new RVar(variables_[i].c_str(), arg_[i]);
      vararray_[i] = var_arg_[i];
    }
    for (unsigned int i = 0; i < dimRange(); ++ i) {
      op_[i] = new ROperation(expressions_[i].c_str(), maxDimDomain, vararray_);
    }
  } // void setup(const std::string& variable, const std::vector< std::string >& expressions)

  void cleanup()
  {
    for (unsigned int i = 0; i < dimRange(); ++i) {
      delete op_[i];
    }
    for (unsigned int i = 0; i < maxDimDomain; ++i) {
      delete var_arg_[i];
      delete arg_[i];
    }
  } // void cleanup()

  std::string                variable_;
  std::vector< std::string > variables_;
  std::vector< std::string > expressions_;
  unsigned int actualDimRange_;
  mutable DomainFieldType* arg_[maxDimDomain];
  RVar* var_arg_[maxDimDomain];
  RVar* vararray_[maxDimDomain];
  ROperation* op_[maxDimRange];
}; // class Expression

} // namespace Function
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_FUNCTION_EXPRESSION_HH
<commit_msg>[function.expression] added additional evaluate()s<commit_after>#ifndef DUNE_STUFF_FUNCTION_EXPRESSION_HH
#define DUNE_STUFF_FUNCTION_EXPRESSION_HH

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#else
  #include "config.h"
#endif // ifdef HAVE_CMAKE_CONFIG

#include <sstream>
#include <vector>

#if HAVE_EIGEN
  #include <Eigen/Core>
#endif // HAVE_EIGEN

#include <dune/common/fvector.hh>
#include <dune/common/dynvector.hh>
#include <dune/common/exceptions.hh>

#ifdef HAVE_DUNE_FEM
  #include <dune/fem/function/common/function.hh>
  #include <dune/fem/space/common/functionspace.hh>
#endif // HAVE_DUNE_FEM

#include <dune/stuff/common/parameter/tree.hh>
#include <dune/stuff/common/string.hh>

#include "expression/mathexpr.hh"
#include "interface.hh"

namespace Dune {
namespace Stuff {
namespace Function {

/**
  \brief  Provides a function which evaluates a given mathematical expression at runtime.

          Given a mathematical expression as a string, a domain \f$ K_d^{m \geq 1} \f$ and a range \f$ K_r^{n \geq 1}
          \f$ this function represents the map
          \f{eqnarray}
            f:K_d^m \to K_r^n\\
            x = (x_1, \dots, x_m)' \mapsto (f_1(x), \dots f_n(x))',
          \f}
          where \f$ K_d \f$ is the DomainType and \f$ K_r \f$ is the RangeType, usually a power of \f$ \mathcal{R} \f$.
          The name of the variable as well as the \f$ n \f$ expressions of \f$f_1, \dots, f_n\f$ have to be given in a
          Dune::ParameterTree in the following form:
\code variable: x
expression.0: 2*x[0]
expression.1: sin(x[1])*x[0]\endcode
          There have to exist at least \f$n\f$ expressions; the entries of the variable are indexed by \f$[i]\f$ for
          \f$ 0 \leq i \leq m - 1 \f$.
 **/
template< class DomainFieldImp, int maxDimDomain, class RangeFieldImp, int maxDimRange >
class Expression
  : public Interface< DomainFieldImp, maxDimDomain, RangeFieldImp, maxDimRange >
{
public:
  typedef DomainFieldImp DomainFieldType;

  typedef RangeFieldImp RangeFieldType;

  typedef Interface< DomainFieldImp, maxDimDomain, RangeFieldImp, maxDimRange > BaseType;

  typedef Expression< DomainFieldImp, maxDimDomain, RangeFieldImp, maxDimRange > ThisType;

  Expression(const std::string _variable, const std::string _expression)
  {
    const std::vector< std::string > expressions(1, _expression);
    setup(_variable, expressions);
  } // Expression(const std::string variable, const std::string expression)

  Expression(const std::string _variable, const std::vector< std::string > _expressions)
  {
    setup(_variable, _expressions);
  } // Expression(const std::string variable, const std::vector< std::string >& expressions)

  Expression(const ThisType& other)
  {
    setup(other.variable(), other.expression());
  } // Expression(const ThisType& other)

  static ThisType createFromParamTree(const Dune::ParameterTree& paramTree)
  {
    const Dune::Stuff::Common::ExtendedParameterTree extendedParamtree(paramTree);
    // get variable
    const std::string variable = extendedParamtree.get< std::string >("variable");
    // get expressions
    const std::vector< std::string > expressions = extendedParamtree.getVector< std::string >("expression", 1);
    // create and return
    return ThisType(variable, expressions);
  } // static ThisType createFromParamTree(const Stuff::Common::ExtendedParameterTree& paramTree)

  ThisType& operator=(const ThisType& other)
  {
    if (this != &other) {
      cleanup();
      setup(other.variable(), other.expression());
    }
    return this;
  } // ThisType& operator=(const ThisType& other)

  ~Expression()
  {
    cleanup();
  } // ~Expression()

  void report(const std::string name = "stuff.function.expression",
              std::ostream& stream = std::cout,
              const std::string& prefix = "") const
  {
    const std::string tmp = name + "(" + variable() + ") = ";
    stream << prefix << tmp;
    if (expression().size() == 1)
        stream << expression()[0] << std::endl;
    else {
      stream << "[ " << expression()[0] << ";" << std::endl;
      const std::string whitespace = Dune::Stuff::Common::whitespaceify(tmp + "[ ");
      for (unsigned int i = 1; i < expression().size() - 1; ++i)
        stream << prefix << whitespace << expression()[i] << ";" << std::endl;
      stream << prefix << whitespace << expression()[expression().size() -1] << " ]" << std::endl;
    }
  } // void report(const std::string, std::ostream&, const std::string&) const

  std::string variable() const
  {
    return variable_;
  }

  const std::vector< std::string > expression() const
  {
    return expressions_;
  }

  unsigned int dimRange() const
  {
    return std::min(int(actualDimRange_), maxDimRange);
  }

  //! needed for Interface
  virtual void evaluate(const Dune::FieldVector< DomainFieldImp, maxDimDomain >& arg, Dune::FieldVector< RangeFieldImp, maxDimRange >& ret) const
  {
    // ensure right dimensions
    assert(arg.size() <= maxDimDomain);
    assert(ret.size() <= dimRange());
    // arg
    for (typename Dune::FieldVector< DomainFieldImp, maxDimDomain >::size_type i = 0; i < arg.size(); ++i) {
      *(arg_[i]) = arg[i];
    }
    // ret
    for (typename Dune::FieldVector< RangeFieldImp, maxDimRange >::size_type i = 0; i < ret.size(); ++i) {
      ret[i] = op_[i]->Val();
    }
  }

  template< class DomainVectorType, class RangeVectorType >
  void evaluate(const Dune::DenseVector< DomainVectorType >& arg, Dune::DenseVector< RangeVectorType >& ret) const
  {
    // ensure right dimensions
    assert(arg.size() <= maxDimDomain);
    assert(ret.size() <= dimRange());
    // arg
    for (typename Dune::DenseVector< DomainVectorType >::size_type i = 0; i < arg.size(); ++i) {
      *(arg_[i]) = arg[i];
    }
    // ret
    for (typename Dune::DenseVector< RangeVectorType >::size_type i = 0; i < ret.size(); ++i) {
      ret[i] = op_[i]->Val();
    }
  }

#ifdef HAVE_EIGEN
  /**
   * \attention ret is resized to size dimRange()!
   */
  void evaluate(const Eigen::VectorXd& arg, Eigen::VectorXd& ret) const
  {
    // ensure right dimensions
    assert(arg.size() <= maxDimDomain);
    ret.resize(dimRange());
    // arg
    for (int i = 0; i < arg.size(); ++ i) {
      *(arg_[i]) = arg(i);
    }
    // ret
    for (int i = 0; i < ret.size(); ++ i) {
      ret(i) = op_[i]->Val();
    }
  } // void evaluate(const Eigen::VectorXd& arg, Eigen::VectorXd& ret) const
#endif // HAVE_EIGEN

  using BaseType::evaluate;

private:
  void setup(const std::string& _variable, const std::vector< std::string >& _expressions)
  {
    assert(maxDimDomain > 0);
    assert(maxDimRange > 0);
    // set expressions
    if (_expressions.size() < 1)
      DUNE_THROW(Dune::InvalidStateException,"\nError: Given 'expressions'-vector is empty!");
    actualDimRange_ = std::min(int(_expressions.size()), maxDimRange);
    expressions_ = _expressions;
    // set variable (i.e. "x")
    variable_ = _variable;
    // fill variables (i.e. "x[0]", "x[1]", ...)
    for (int i = 0; i < maxDimDomain; ++i) {
      std::stringstream variableStream;
      variableStream << variable_ << "[" << i << "]";
      variables_.push_back(variableStream.str());
    }
    // create epressions
    for (unsigned int i = 0; i < maxDimDomain; ++i) {
      arg_[i] = new DomainFieldType(0.0);
      var_arg_[i] = new RVar(variables_[i].c_str(), arg_[i]);
      vararray_[i] = var_arg_[i];
    }
    for (unsigned int i = 0; i < dimRange(); ++ i) {
      op_[i] = new ROperation(expressions_[i].c_str(), maxDimDomain, vararray_);
    }
  } // void setup(const std::string& variable, const std::vector< std::string >& expressions)

  void cleanup()
  {
    for (unsigned int i = 0; i < dimRange(); ++i) {
      delete op_[i];
    }
    for (unsigned int i = 0; i < maxDimDomain; ++i) {
      delete var_arg_[i];
      delete arg_[i];
    }
  } // void cleanup()

  std::string                variable_;
  std::vector< std::string > variables_;
  std::vector< std::string > expressions_;
  unsigned int actualDimRange_;
  mutable DomainFieldType* arg_[maxDimDomain];
  RVar* var_arg_[maxDimDomain];
  RVar* vararray_[maxDimDomain];
  ROperation* op_[maxDimRange];
}; // class Expression

} // namespace Function
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_FUNCTION_EXPRESSION_HH
<|endoftext|>


<commit_before>#include "script.hpp"
#include "filesystem.hpp"
#include "logger.hpp"

class LuaScript
{
public:
    LuaScript()
    {
        InitLua();
    }

    ~LuaScript()
    {
        HaltLua();
    }

    // call a lua function.
    // you must specify the quantity of of params and returns.
    int CallLua(std::string func, int num_params, int num_returns)
    {
        // on error, execute lua function debug.traceback
        // debug is a table, put it on the stack
        lua_getglobal(mLuaState, "debug");

        // -1 is the top of the stack
        lua_getfield(mLuaState, -1, "traceback");

        // traceback is on top, remove debug from 2nd spot
        lua_remove(mLuaState, -2);

        mErrorHandlerStackIndex = lua_gettop(mLuaState);

        // get the lua function and execute it
        lua_getglobal(mLuaState, func.c_str());
        const int ret = lua_pcall(mLuaState, num_params, num_returns, mErrorHandlerStackIndex);
        if (ret)
        {
            printf("\nLua call failed (%s): %s\n",
                ErrorToString(ret).c_str(),
                lua_tostring(mLuaState, -1));
        }

        // remove the error handler from the stack
        lua_pop(mLuaState, 1);

        return ret;
    }

    bool FunctionExists(std::string func)
    {
        // try to put the function on top of the stack
        lua_getglobal(mLuaState, func.c_str());

        // check that value on top of stack is not nil
        bool ret = !lua_isnil(mLuaState, -1);

        // get rid of the value we put on the stack
        lua_pop(mLuaState, 1);

        return ret;
    }

    lua_State* State()
    {
        return mLuaState;
    }

private:
    void InitLua()
    {
        mLuaState = luaL_newstate();
        luaL_openlibs(mLuaState);

        set_redirected_print();
        lua_register(mLuaState, "h_echo", HAPI_echo);
    }

    void HaltLua()
    {
        lua_close(mLuaState);
    }

    static std::string LuaTypeToString(int index)
    {
        switch (index)
        {
        case LUA_TNIL:            return "nil";
        case LUA_TNUMBER:         return "number";
        case LUA_TBOOLEAN:        return "boolean";
        case LUA_TSTRING:         return "string";
        case LUA_TTABLE:          return "table";
        case LUA_TFUNCTION:       return "function";
        case LUA_TUSERDATA:       return "userdata";
        case LUA_TTHREAD:         return "thread";
        case LUA_TLIGHTUSERDATA:  return "light userdata";
        default:                  return "unknown type";
        }
    }

    static std::string ErrorToString(int resultcode)
    {
        switch (resultcode)
        {
        case 0:             return "Success";
        case LUA_ERRRUN:    return "Runtime error";
        case LUA_ERRSYNTAX: return "Syntax error";
        case LUA_ERRERR:    return "Error with error alert mechanism.";
        case LUA_ERRFILE:   return "Couldn't open or read file";
        default:            return "Unknown error: " + std::to_string(resultcode);
        }
    }

    static int script_log(lua_State* L)
    {
        const int nargs = lua_gettop(L);
        for (int i = 1; i <= nargs; ++i)
        {
            if (lua_isstring(L, i))
            {
                LOG_INFO(lua_tostring(L, i));
            }
            else
            {
                LOG_ERROR("TODO: Print this type");
            }
        }
        return 0;
    }

    // this is the API function we expose to lua.
    static int HAPI_echo(lua_State* L)
    {
        int args_from_lua = lua_gettop(L);

        // in this example, we'll take any number of args
        printf("HAPI_echo() called with %d arguments\n", args_from_lua);
        for (int n = 1; n <= args_from_lua; ++n)
        {
            printf(" * arg %02d (%s):\t%s\n",
                n,
                LuaTypeToString(lua_type(L, n)).c_str(),
                lua_tostring(L, n));
            // note: lua_tostring coerces stack value!
        }

        // return (123, "abc") to lua
        lua_pushnumber(L, 123);
        lua_pushstring(L, "abc");
        return 2; // 2 return values are on the stack

    }

    int set_redirected_print()
    {
        lua_getglobal(mLuaState, "_G");
        lua_register(mLuaState, "print", script_log);
        lua_pop(mLuaState, 1); // global table
        return 0;
    }

private:
    lua_State* mLuaState = nullptr;
    int mErrorHandlerStackIndex = 0;
};

Script::Script()
{

}

Script::~Script()
{

}

bool Script::Init(FileSystem& fs)
{
    const std::string myfile = fs.GameData().BasePath() + "data/scripts/main.lua";

    mScript = std::make_unique<LuaScript>();

    printf("loading/executing lua file %s\n", myfile.c_str());
    luaL_dofile(mScript->State(), myfile.c_str());

    return true;
}

void Script::Update()
{
    const std::string myfn = "Update";
    const int res = mScript->CallLua(myfn, 0, 0);
    if (res)
    {
        printf("%d, returned from call to %s\n", res, myfn.c_str());
    }
}
<commit_msg>remove example api and printfs<commit_after>#include "script.hpp"
#include "filesystem.hpp"
#include "logger.hpp"

class LuaScript
{
public:
    LuaScript()
    {
        InitLua();
    }

    ~LuaScript()
    {
        HaltLua();
    }

    // call a lua function.
    // you must specify the quantity of of params and returns.
    int CallLua(std::string func, int num_params, int num_returns)
    {
        // on error, execute lua function debug.traceback
        // debug is a table, put it on the stack
        lua_getglobal(mLuaState, "debug");

        // -1 is the top of the stack
        lua_getfield(mLuaState, -1, "traceback");

        // traceback is on top, remove debug from 2nd spot
        lua_remove(mLuaState, -2);

        mErrorHandlerStackIndex = lua_gettop(mLuaState);

        // get the lua function and execute it
        lua_getglobal(mLuaState, func.c_str());
        const int ret = lua_pcall(mLuaState, num_params, num_returns, mErrorHandlerStackIndex);
        if (ret)
        {
            LOG_ERROR("Lua call failed (" << ErrorToString(ret) << ": " << lua_tostring(mLuaState, -1));
        }

        // remove the error handler from the stack
        lua_pop(mLuaState, 1);

        return ret;
    }

    bool FunctionExists(std::string func)
    {
        // try to put the function on top of the stack
        lua_getglobal(mLuaState, func.c_str());

        // check that value on top of stack is not nil
        bool ret = !lua_isnil(mLuaState, -1);

        // get rid of the value we put on the stack
        lua_pop(mLuaState, 1);

        return ret;
    }

    lua_State* State()
    {
        return mLuaState;
    }

private:
    void InitLua()
    {
        mLuaState = luaL_newstate();
        luaL_openlibs(mLuaState);

        set_redirected_print();
    }

    void HaltLua()
    {
        lua_close(mLuaState);
    }

    static std::string LuaTypeToString(int index)
    {
        switch (index)
        {
        case LUA_TNIL:            return "nil";
        case LUA_TNUMBER:         return "number";
        case LUA_TBOOLEAN:        return "boolean";
        case LUA_TSTRING:         return "string";
        case LUA_TTABLE:          return "table";
        case LUA_TFUNCTION:       return "function";
        case LUA_TUSERDATA:       return "userdata";
        case LUA_TTHREAD:         return "thread";
        case LUA_TLIGHTUSERDATA:  return "light userdata";
        default:                  return "unknown type";
        }
    }

    static std::string ErrorToString(int resultcode)
    {
        switch (resultcode)
        {
        case 0:             return "Success";
        case LUA_ERRRUN:    return "Runtime error";
        case LUA_ERRSYNTAX: return "Syntax error";
        case LUA_ERRERR:    return "Error with error alert mechanism.";
        case LUA_ERRFILE:   return "Couldn't open or read file";
        default:            return "Unknown error: " + std::to_string(resultcode);
        }
    }

    static int script_log(lua_State* L)
    {
        const int nargs = lua_gettop(L);
        for (int i = 1; i <= nargs; ++i)
        {
            if (lua_isstring(L, i))
            {
                LOG_INFO(lua_tostring(L, i));
            }
            else
            {
                LOG_ERROR("TODO: Print this type");
            }
        }
        return 0;
    }

    int set_redirected_print()
    {
        lua_getglobal(mLuaState, "_G");
        lua_register(mLuaState, "print", script_log);
        lua_pop(mLuaState, 1); // global table
        return 0;
    }

private:
    lua_State* mLuaState = nullptr;
    int mErrorHandlerStackIndex = 0;
};

Script::Script()
{

}

Script::~Script()
{

}

bool Script::Init(FileSystem& fs)
{
    const std::string myfile = fs.GameData().BasePath() + "data/scripts/main.lua";

    mScript = std::make_unique<LuaScript>();

    luaL_dofile(mScript->State(), myfile.c_str());

    return true;
}

void Script::Update()
{
    const std::string myfn = "Update";
    const int res = mScript->CallLua(myfn, 0, 0);
    if (res)
    {

    }
}
<|endoftext|>


<commit_before><commit_msg>bump version to 0.4.1<commit_after><|endoftext|>


<commit_before><commit_msg>update 335<commit_after><|endoftext|>


<commit_before>#include <cmath>
#include <chrono>
#include <iostream>
#include "SrsEngine.h"

Flashcard SrsEngine::gradeFlashcard(Flashcard flashcard, unsigned int grade) {

    float newEasinessFactor = 0;
    std::time_t nextDate;

    if (grade < 3) {
        flashcard.setRepetitionCount(0);
        flashcard.setInterval(0);
    }
    else {
        newEasinessFactor = flashcard.getEasinessFactor() + (0.1 - (5 - grade) * (0.08 +(5 - grade) * 0.02));

        if (newEasinessFactor < 1.3) {
            flashcard.setEasinessFactor(1.3);
        }
        else {
            flashcard.setEasinessFactor(newEasinessFactor);
        }

        flashcard.setRepetitionCount(flashcard.getRepetitionCount() + 1);

        switch(flashcard.getRepetitionCount()) {
            case 1:
                flashcard.setInterval(1);
                break;

            case 2:
                flashcard.setInterval(6);
                break;

            default:
                float newInterval = ceil((flashcard.getRepetitionCount() - 1) * flashcard.getEasinessFactor());
                flashcard.setInterval(newInterval);
                break;
        }
    }

    if (grade == 3) {
        flashcard.setInterval(0);
    }

    std::chrono::system_clock::time_point today = std::chrono::system_clock::now();
    std::chrono::duration<int,std::ratio<60*60*24> > extraDays (flashcard.getInterval());

    //std::cout << "extraDays are: " << extraDays << std::endl;

    std::chrono::system_clock::time_point newNextDay = today + extraDays;

    flashcard.setNextDate(newNextDay);

    return flashcard;
}
<commit_msg>SrsEngine cleanup<commit_after>#include <cmath>
#include <chrono>
#include <iostream>
#include "SrsEngine.h"

Flashcard SrsEngine::gradeFlashcard(Flashcard flashcard, unsigned int grade) {

    if (grade < 3) {
        flashcard.setRepetitionCount(0);
        flashcard.setInterval(1);
    }
    else {
        float newEasinessFactor = flashcard.getEasinessFactor() + (0.1 - (5 - grade) * (0.08 + (5 - grade) * 0.02));

        if (newEasinessFactor < 1.3) {
            flashcard.setEasinessFactor(1.3);
        }
        else {
            flashcard.setEasinessFactor(newEasinessFactor);
        }

        flashcard.setRepetitionCount(flashcard.getRepetitionCount() + 1);

        switch(flashcard.getRepetitionCount()) {
            case 1:
                flashcard.setInterval(1);
                break;

            case 2:
                flashcard.setInterval(6);
                break;

            default:
                float newInterval = ceil((flashcard.getRepetitionCount() - 1) * flashcard.getEasinessFactor());
                flashcard.setInterval(newInterval);
                break;
        }
    }

    if (grade == 3) {
        flashcard.setInterval(0);
    }

    std::chrono::system_clock::time_point today = std::chrono::system_clock::now();
    std::chrono::duration<int,std::ratio<60*60*24> > extraDays (flashcard.getInterval());

    //std::cout << "extraDays are: " << extraDays << std::endl;

    std::chrono::system_clock::time_point newNextDay = today + extraDays;

    flashcard.setNextDate(newNextDay);

    return flashcard;
}
<|endoftext|>


<commit_before><commit_msg>Minor fix in comments<commit_after><|endoftext|>


<commit_before>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include "Font.h"

#include <algorithm>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <hb-ft.h>
#include <Utility/Unicode.h>

#include "Extensions.h"
#include "Image.h"
#include "TextureTools/Atlas.h"

namespace Magnum { namespace Text {

Font::Font(FontRenderer& renderer, const std::string& fontFile, GLfloat size): _size(size) {
    CORRADE_INTERNAL_ASSERT_OUTPUT(FT_New_Face(renderer.library(), fontFile.c_str(), 0, &_ftFont) == 0);

    finishConstruction();
}

Font::Font(FontRenderer& renderer, const unsigned char* data, std::size_t dataSize, GLfloat size): _size(size) {
    CORRADE_INTERNAL_ASSERT_OUTPUT(FT_New_Memory_Face(renderer.library(), data, dataSize, 0, &_ftFont) == 0);

    finishConstruction();
}

void Font::finishConstruction() {
    CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Set_Char_Size(_ftFont, 0, _size*64, 100, 100) == 0);

    /* Create Harfbuzz font */
    _hbFont = hb_ft_font_create(_ftFont, nullptr);

    #ifndef MAGNUM_TARGET_GLES
    MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);
    #else
    MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg);
    #endif

    /* Set up the texture */
    _texture.setWrapping(Texture2D::Wrapping::ClampToEdge)
        ->setMinificationFilter(Texture2D::Filter::LinearInterpolation)
        ->setMagnificationFilter(Texture2D::Filter::LinearInterpolation);
}

void Font::prerender(const std::string& characters, const Vector2i& atlasSize) {
    glyphs.clear();

    /** @bug Crash when atlas is too small */

    /* Get character codes from string */
    std::vector<std::uint32_t> charCodes;
    charCodes.reserve(characters.size());
    for(std::size_t i = 0; i != characters.size(); ) {
        std::uint32_t codepoint;
        std::tie(codepoint, i) = Corrade::Utility::Unicode::nextChar(characters, i);
        charCodes.push_back(codepoint);
    }

    /* Get character indices */
    std::vector<FT_UInt> charIndices;
    charIndices.push_back(0);
    for(std::uint32_t charCode: charCodes)
        charIndices.push_back(FT_Get_Char_Index(_ftFont, charCode));

    /* Remove duplicates (e.g. uppercase and lowercase mapped to same glyph) */
    std::sort(charIndices.begin(), charIndices.end());
    charIndices.erase(std::unique(charIndices.begin(), charIndices.end()), charIndices.end());

    /* Sizes of all characters */
    std::vector<Vector2i> charSizes;
    charSizes.reserve(charIndices.size());
    for(FT_UInt c: charIndices) {
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(_ftFont, c, FT_LOAD_DEFAULT) == 0);
        charSizes.push_back((Vector2i(_ftFont->glyph->metrics.width, _ftFont->glyph->metrics.height))/64);
    }

    /* Create texture atlas */
    std::vector<Rectanglei> charPositions = TextureTools::atlas(atlasSize, charSizes);

    /* Render all characters to the atlas and create character map */
    glyphs.reserve(charPositions.size());
    unsigned char* pixmap = new unsigned char[atlasSize.product()]();
    Image2D image(atlasSize, Image2D::Format::Red, Image2D::Type::UnsignedByte, pixmap);
    for(std::size_t i = 0; i != charPositions.size(); ++i) {
        /* Load and render glyph */
        /** @todo B&W only */
        FT_GlyphSlot glyph = _ftFont->glyph;
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(_ftFont, charIndices[i], FT_LOAD_DEFAULT) == 0);
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) == 0);

        /* Copy rendered bitmap to texture image */
        const FT_Bitmap& bitmap = glyph->bitmap;
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.width-charPositions[i].width()) <= 2);
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.rows-charPositions[i].height()) <= 2);
        for(std::int32_t yin = 0, yout = charPositions[i].bottom(), ymax = bitmap.rows; yin != ymax; ++yin, ++yout)
            for(std::int32_t xin = 0, xout = charPositions[i].left(), xmax = bitmap.width; xin != xmax; ++xin, ++xout)
                pixmap[yout*atlasSize.x() + xout] = bitmap.buffer[(bitmap.rows-yin-1)*bitmap.width + xin];

        /* Save character texture position and texture coordinates for given character index */
        CORRADE_INTERNAL_ASSERT_OUTPUT(glyphs.insert({charIndices[i], std::make_tuple(
            Rectangle::fromSize(Vector2(glyph->bitmap_left, glyph->bitmap_top-charPositions[i].height())/_size,
                                Vector2(charPositions[i].size())/_size),
            Rectangle(Vector2(charPositions[i].bottomLeft())/atlasSize,
                      Vector2(charPositions[i].topRight())/atlasSize)
        )}).second);
    }

    /* Set texture data */
    #ifndef MAGNUM_TARGET_GLES
    _texture.setImage(0, Texture2D::InternalFormat::R8, &image);
    #else
    _texture.setImage(0, Texture2D::InternalFormat::Red, &image);
    #endif
}

void Font::destroy() {
    if(!_ftFont) return;

    hb_font_destroy(_hbFont);
    FT_Done_Face(_ftFont);
}

void Font::move() {
    _hbFont = nullptr;
    _ftFont = nullptr;
}

Font::~Font() { destroy(); }

Font::Font(Font&& other): glyphs(std::move(other.glyphs)), _texture(std::move(other._texture)), _ftFont(other._ftFont), _hbFont(other._hbFont), _size(other._size) {
    other.move();
}

Font& Font::operator=(Font&& other) {
    destroy();

    glyphs = std::move(other.glyphs);
    _texture = std::move(other._texture);
    _ftFont = other._ftFont;
    _hbFont = other._hbFont;
    _size = other._size;

    other.move();
    return *this;
}

const std::tuple<Rectangle, Rectangle>& Font::operator[](std::uint32_t character) const {
    auto it = glyphs.find(character);

    if(it == glyphs.end())
        return glyphs.at(0);
    return it->second;
}

}}
<commit_msg>Text: code cleanup -- merged two loops into one.<commit_after>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include "Font.h"

#include <algorithm>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <hb-ft.h>
#include <Utility/Unicode.h>

#include "Extensions.h"
#include "Image.h"
#include "TextureTools/Atlas.h"

namespace Magnum { namespace Text {

Font::Font(FontRenderer& renderer, const std::string& fontFile, GLfloat size): _size(size) {
    CORRADE_INTERNAL_ASSERT_OUTPUT(FT_New_Face(renderer.library(), fontFile.c_str(), 0, &_ftFont) == 0);

    finishConstruction();
}

Font::Font(FontRenderer& renderer, const unsigned char* data, std::size_t dataSize, GLfloat size): _size(size) {
    CORRADE_INTERNAL_ASSERT_OUTPUT(FT_New_Memory_Face(renderer.library(), data, dataSize, 0, &_ftFont) == 0);

    finishConstruction();
}

void Font::finishConstruction() {
    CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Set_Char_Size(_ftFont, 0, _size*64, 100, 100) == 0);

    /* Create Harfbuzz font */
    _hbFont = hb_ft_font_create(_ftFont, nullptr);

    #ifndef MAGNUM_TARGET_GLES
    MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);
    #else
    MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg);
    #endif

    /* Set up the texture */
    _texture.setWrapping(Texture2D::Wrapping::ClampToEdge)
        ->setMinificationFilter(Texture2D::Filter::LinearInterpolation)
        ->setMagnificationFilter(Texture2D::Filter::LinearInterpolation);
}

void Font::prerender(const std::string& characters, const Vector2i& atlasSize) {
    glyphs.clear();

    /** @bug Crash when atlas is too small */

    /* Get glyph codes from characters */
    std::vector<FT_UInt> charIndices;
    charIndices.reserve(characters.size()+1);
    charIndices.push_back(0);
    for(std::size_t i = 0; i != characters.size(); ) {
        std::uint32_t codepoint;
        std::tie(codepoint, i) = Corrade::Utility::Unicode::nextChar(characters, i);
        charIndices.push_back(FT_Get_Char_Index(_ftFont, codepoint));
    }

    /* Remove duplicates (e.g. uppercase and lowercase mapped to same glyph) */
    std::sort(charIndices.begin(), charIndices.end());
    charIndices.erase(std::unique(charIndices.begin(), charIndices.end()), charIndices.end());

    /* Sizes of all characters */
    std::vector<Vector2i> charSizes;
    charSizes.reserve(charIndices.size());
    for(FT_UInt c: charIndices) {
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(_ftFont, c, FT_LOAD_DEFAULT) == 0);
        charSizes.push_back((Vector2i(_ftFont->glyph->metrics.width, _ftFont->glyph->metrics.height))/64);
    }

    /* Create texture atlas */
    std::vector<Rectanglei> charPositions = TextureTools::atlas(atlasSize, charSizes);

    /* Render all characters to the atlas and create character map */
    glyphs.reserve(charPositions.size());
    unsigned char* pixmap = new unsigned char[atlasSize.product()]();
    Image2D image(atlasSize, Image2D::Format::Red, Image2D::Type::UnsignedByte, pixmap);
    for(std::size_t i = 0; i != charPositions.size(); ++i) {
        /* Load and render glyph */
        /** @todo B&W only */
        FT_GlyphSlot glyph = _ftFont->glyph;
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(_ftFont, charIndices[i], FT_LOAD_DEFAULT) == 0);
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) == 0);

        /* Copy rendered bitmap to texture image */
        const FT_Bitmap& bitmap = glyph->bitmap;
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.width-charPositions[i].width()) <= 2);
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.rows-charPositions[i].height()) <= 2);
        for(std::int32_t yin = 0, yout = charPositions[i].bottom(), ymax = bitmap.rows; yin != ymax; ++yin, ++yout)
            for(std::int32_t xin = 0, xout = charPositions[i].left(), xmax = bitmap.width; xin != xmax; ++xin, ++xout)
                pixmap[yout*atlasSize.x() + xout] = bitmap.buffer[(bitmap.rows-yin-1)*bitmap.width + xin];

        /* Save character texture position and texture coordinates for given character index */
        CORRADE_INTERNAL_ASSERT_OUTPUT(glyphs.insert({charIndices[i], std::make_tuple(
            Rectangle::fromSize(Vector2(glyph->bitmap_left, glyph->bitmap_top-charPositions[i].height())/_size,
                                Vector2(charPositions[i].size())/_size),
            Rectangle(Vector2(charPositions[i].bottomLeft())/atlasSize,
                      Vector2(charPositions[i].topRight())/atlasSize)
        )}).second);
    }

    /* Set texture data */
    #ifndef MAGNUM_TARGET_GLES
    _texture.setImage(0, Texture2D::InternalFormat::R8, &image);
    #else
    _texture.setImage(0, Texture2D::InternalFormat::Red, &image);
    #endif
}

void Font::destroy() {
    if(!_ftFont) return;

    hb_font_destroy(_hbFont);
    FT_Done_Face(_ftFont);
}

void Font::move() {
    _hbFont = nullptr;
    _ftFont = nullptr;
}

Font::~Font() { destroy(); }

Font::Font(Font&& other): glyphs(std::move(other.glyphs)), _texture(std::move(other._texture)), _ftFont(other._ftFont), _hbFont(other._hbFont), _size(other._size) {
    other.move();
}

Font& Font::operator=(Font&& other) {
    destroy();

    glyphs = std::move(other.glyphs);
    _texture = std::move(other._texture);
    _ftFont = other._ftFont;
    _hbFont = other._hbFont;
    _size = other._size;

    other.move();
    return *this;
}

const std::tuple<Rectangle, Rectangle>& Font::operator[](std::uint32_t character) const {
    auto it = glyphs.find(character);

    if(it == glyphs.end())
        return glyphs.at(0);
    return it->second;
}

}}
<|endoftext|>


<commit_before><commit_msg>DN-154 Display Names only shown in Nearby Chat History when a user logs back in even if Usernames were shown in Chat during previous session<commit_after><|endoftext|>


<commit_before><commit_msg>Replaced gSavedSettings.get* calls in texture console with LLCachedControls<commit_after><|endoftext|>