<commit_before>/**
   \file undistort.cc

   Apply Lensfun corrections to a PNM file in place.  This means, the original
   file is overwritten.  The command line parameters are:
   - path to the PNM file
   - x coordinate of top left corner
   - y coordinate of top left corner
   - x coordinate of top right corner
   - y coordinate of top right corner
   - x coordinate of bottom left corner
   - y coordinate of bottom left corner
   - x coordinate of bottom right corner
   - y coordinate of bottom right corner
   - Lensfun name of camera make
   - Lensfun name of camera model
   - Lensfun name of lens make
   - Lensfun name of lens model

   All coordinates are pixel coordinates, with the top left of the image the
   origin.  The corners must be the corners of a perfect rectangle which was
   taken a picture of, e.g. a sheet of paper.  These are used for the
   perspective correction as well as the rotation, so that the edges of the
   rectangle are parellel to the image borders.

   The program returns the position and the dimensions of the rectangle in
   the output image to stdout in JSON format:

   \code{.json}
   [x₀, y₀, width, height]
   \endcode

   Here, x₀ and y₀ are the coordinates of the top left corner, and width and
   height are the dimensions of the rectangle.

   This program does not apply colour corrections such as vignetting
   correction, as those are handled by kamscan.py using flat field images.
*/
#include <Python.h>
#include <fstream>
#include <vector>
#include <iterator>
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include "lensfun/lensfun.h"

/** Class for bitmap data.

  In case of 2 bytes per channel, network byte order is assumed. */
class Image {
public:
    Image(int width, int height, int channel_size, int channels);
    Image() {};
    Image(const Image &image);
    /** Get the channel intensity at a certian coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \return raw integer value of the intensity of this channel at this
        position
    */
    int get(int x, int y, int channel);
    /** Get the channel intensity at a certian coordinate.  The coordinates are
      floats and may contain fractions.  In this case, the intensity is
      calculated using bilinear interpolation between the four pixels around
      this coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \return raw integer value of the intensity of this channel at this
        position
    */
    int get(float x, float y, int channel);
    /** Set the channel intensity at a certian coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \param value raw integer value of the intensity of this channel at this
        position
    */
    void set(int x, int y, int channel, int value);
    /** Determine the channel descriptions.  This is used by Lensfun internally
      and necessary if you want to apply colour corrections, e.g. vignetting
      correction.
      \return the components of each pixel
    */
    int components();
    /** Determine the pixel format à la Lensfun.  It is derived from
      channel_size.
      \return the pixel format as it is needed by Lensfun
     */
    lfPixelFormat pixel_format();
    int width, height; ///< width and height of the image in pixels
    int channels; ///< number of channels; may be 1 (greyscale) or 3 (RGB)
    /** the raw data (1:1 dump of the PNM content, without header)
     */
    std::vector<unsigned char> data;

private:
    friend std::istream& operator>>(std::istream &inputStream, Image &other);
    friend std::ostream& operator<<(std::ostream &outputStream, const Image &other);
    int channel_size; ///< width of one channel in bytes; may be 1 or 2
};

Image::Image(int width, int height, int channel_size, int channels) :
    width(width), height(height), channel_size(channel_size), channels(channels)
{
    data.resize(width * height * channel_size * channels);
}

Image::Image(const Image &image) :
    width(image.width), height(image.height), channel_size(image.channel_size), channels(image.channels) {
    data.resize(width * height * channel_size * channels);
}

int Image::get(int x, int y, int channel) {
    if (x < 0 || x >= width || y < 0 || y >= height)
        return 0;
    int position = channel_size * (channels * (y * width + x) + channel);
    int result = static_cast<int>(data[position]);
    if (channel_size == 2)
        result = (result << 8) + static_cast<int>(data[position + 1]);
    return result;
}

int Image::get(float x, float y, int channel) {
    float dummy;
    int x0 = static_cast<int>(x);
    int y0 = static_cast<int>(y);
    float i0 = static_cast<float>(get(x0, y0, channel));
    float i1 = static_cast<float>(get(x0 + 1, y0, channel));
    float i2 = static_cast<float>(get(x0, y0 + 1, channel));
    float i3 = static_cast<float>(get(x0 + 1, y0 + 1, channel));
    float fraction_x = std::modf(x, &dummy);
    float i01 = (1 - fraction_x) * i0 + fraction_x * i1;
    float i23 = (1 - fraction_x) * i2 + fraction_x * i3;
    float fraction_y = std::modf(y, &dummy);
    return static_cast<int>(std::round((1 - fraction_y) * i01 + fraction_y * i23));
}

void Image::set(int x, int y, int channel, int value) {
    if (x >= 0 && x < width && y >= 0 && y < height) {
        int position = channel_size * (channels * (y * width + x) + channel);
        if (channel_size == 1)
            data[position] = static_cast<unsigned char>(value);
        else if (channel_size == 2) {
            data[position] = static_cast<unsigned char>(value >> 8);
            data[position + 1] = static_cast<unsigned char>(value & 256);
        }
    }
}

int Image::components() {
    switch (channels) {
    case 1:
        return LF_CR_1(INTENSITY);
    case 3:
        return LF_CR_3(RED, GREEN, BLUE);
    default:
        throw std::runtime_error("Invalid value of 'channels'.");
    }
}

lfPixelFormat Image::pixel_format() {
    switch (channel_size) {
    case 1:
        return LF_PF_U8;
    case 2:
        return LF_PF_U16;
    default:
        throw std::runtime_error("Invalid value of 'channel_size'.");
    }
}

std::istream& operator>>(std::istream &inputStream, Image &other)
{
    std::string magic_number;
    int maximum_color_value;
    inputStream >> magic_number;
    if (magic_number == "P5")
        other.channels = 1;
    else if (magic_number == "P6")
        other.channels = 3;
    else
        throw std::runtime_error("Invalid input file.  Must start with 'P5' or 'P6'.");
    inputStream >> other.width >> other.height >> maximum_color_value;
    inputStream.get(); // skip the trailing white space
    switch (maximum_color_value) {
    case 255:
        other.channel_size = 1;
        break;
    case 65535:
        other.channel_size = 2;
        break;
    default:
        throw std::runtime_error("Invalid PPM file: Maximum color value must be 255 or 65535.");
    }
    size_t size = other.width * other.height * other.channel_size * other.channels;
    other.data.resize(size);
    inputStream.read(reinterpret_cast<char*>(other.data.data()), size);
    return inputStream;
}

std::ostream& operator<<(std::ostream &outputStream, const Image &other)
{
    outputStream << (other.channels == 3 ? "P6" : "P5") << "\n"
                 << other.width << " "
                 << other.height << "\n"
                 << (other.channel_size == 1 ? "255" : "65535") << "\n";
    outputStream.write(reinterpret_cast<const char*>(other.data.data()), other.data.size());
    return outputStream;
}

static PyObject *undistort(PyObject *self, PyObject *args) {
    const char *filename, *camera_make, *camera_model, *lens_make, *lens_model;
    float x0, y0, x1, y1, x2, y2, x3, y3;
    PyArg_ParseTuple(args, "sffffffffssss", &filename, &x0, &y0, &x1, &y1, &x2, &y2, &x3, &y3,
                     &camera_make, &camera_model, &lens_make, &lens_model);

    lfDatabase ldb;

    if (ldb.Load() != LF_NO_ERROR) {
        PyErr_SetString(PyExc_RuntimeError, "Database could not be loaded");
        return NULL;
    }

    const lfCamera *camera;
    const lfCamera **cameras = ldb.FindCamerasExt(camera_make, camera_model);
    if (cameras && !cameras[1])
        camera = cameras[0];
    else {
        std::vector<char> buffer(std::snprintf(nullptr, 0, "Cannot find unique camera in database.  %i cameras found.",
                                               (int)sizeof(cameras)));
        std::snprintf(&buffer[0], buffer.size(), "Cannot find unique camera in database.  %i cameras found.",
                      (int)sizeof(cameras));
        PyErr_SetString(PyExc_RuntimeError, buffer.data());
        lf_free(cameras);
        return NULL;
    }
    lf_free(cameras);

    const lfLens *lens;
    const lfLens **lenses = ldb.FindLenses(camera, lens_make, lens_model);
    if (lenses && !lenses[1]) {
        lens = lenses[0];
    } else if (!lenses) {
        PyErr_SetString(PyExc_RuntimeError, "Cannot find lens in database");
        lf_free(lenses);
        return NULL;
    } else {
        PyErr_SetString(PyExc_RuntimeError, "Lens name ambiguous");
        lf_free(lenses);
        return NULL;
    }
    lf_free(lenses);

    Image image;
    {
        std::ifstream file(filename, std::ios::binary);
        file >> image;
    }

    lfModifier modifier(camera->CropFactor, image.width, image.height, image.pixel_format());
    lfModifier pc_coord_modifier(camera->CropFactor, image.width, image.height, image.pixel_format(), true);
    lfModifier back_modifier(camera->CropFactor, image.width, image.height, image.pixel_format(), true);
    if (!modifier.EnableDistortionCorrection(lens, 50) || !back_modifier.EnableDistortionCorrection(lens, 50) ||
        !pc_coord_modifier.EnableDistortionCorrection(lens, 50)) {
        PyErr_SetString(PyExc_RuntimeError, "Failed to activate undistortion");
        return NULL;
    }
    if (image.channels == 3)
        if (!modifier.EnableTCACorrection(lens, 50)) {
            PyErr_SetString(PyExc_RuntimeError, "Failed to activate un-TCA");
            return NULL;
        }
    std::vector<float> x, y;
    x.push_back(x0);
    y.push_back(y0);

    x.push_back(x2);
    y.push_back(y2);

    x.push_back(x1);
    y.push_back(y1);

    x.push_back(x3);
    y.push_back(y3);

    x.push_back(x0);
    y.push_back(y0);

    x.push_back(x1);
    y.push_back(y1);
    std::vector<float> x_undist, y_undist;
    for (int i = 0; i < x.size(); i++) {
        float result[2];
        pc_coord_modifier.ApplyGeometryDistortion(x[i], y[i], 1, 1, result);
        x_undist.push_back(result[0]);
        y_undist.push_back(result[1]);
    }
    if (!modifier.EnablePerspectiveCorrection(lens, 50, x_undist.data(), y_undist.data(), 6, 0) ||
        !back_modifier.EnablePerspectiveCorrection(lens, 50, x_undist.data(), y_undist.data(), 6, 0)) {
        PyErr_SetString(PyExc_RuntimeError, "Failed to activate perspective correction");
        return NULL;
    }

    std::vector<float> res(image.width * image.height * 2 * image.channels);
    if (image.channels == 3)
        modifier.ApplySubpixelGeometryDistortion(0, 0, image.width, image.height, res.data());
    else
        modifier.ApplyGeometryDistortion(0, 0, image.width, image.height, res.data());
    Image new_image = image;
    for (int x = 0; x < image.width; x++)
        for (int y = 0; y < image.height; y++) {
            int position = 2 * image.channels * (y * image.width + x);
            float source_x_R = res[position];
            float source_y_R = res[position + 1];
            new_image.set(x, y, 0, image.get(source_x_R, source_y_R, 0));
            if (image.channels == 3) {
                float source_x_G = res[position + 2];
                float source_y_G = res[position + 3];
                float source_x_B = res[position + 4];
                float source_y_B = res[position + 5];
                new_image.set(x, y, 1, image.get(source_x_G, source_y_G, 1));
                new_image.set(x, y, 2, image.get(source_x_B, source_y_B, 2));
            }
        }
    std::ofstream file(filename, std::ios::binary);
    file << new_image;

    for (int i = 0; i < 4; i++) {
        float result[2];
        back_modifier.ApplyGeometryDistortion(x[i], y[i], 1, 1, result);
        x[i] = result[0];
        y[i] = result[1];
    }

    return Py_BuildValue("ffff", std::min(x[0], x[2]), std::min(y[0], y[1]),
                         std::max(x[1], x[3]) - std::min(x[0], x[2]), std::max(y[2], y[3]) - std::min(y[0], y[1]));
}

static PyMethodDef UndistortMethods[] = {
    {"undistort",  undistort, METH_VARARGS, "Undistort PNM image data."},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef undistortmodule = {
   PyModuleDef_HEAD_INIT, "undistort", NULL, -1, UndistortMethods
};

PyMODINIT_FUNC
PyInit_undistort(void)
{
    return PyModule_Create(&undistortmodule);
}
<commit_msg>Added FixMe.<commit_after>/**
   \file undistort.cc

   Apply Lensfun corrections to a PNM file in place.  This means, the original
   file is overwritten.  The command line parameters are:
   - path to the PNM file
   - x coordinate of top left corner
   - y coordinate of top left corner
   - x coordinate of top right corner
   - y coordinate of top right corner
   - x coordinate of bottom left corner
   - y coordinate of bottom left corner
   - x coordinate of bottom right corner
   - y coordinate of bottom right corner
   - Lensfun name of camera make
   - Lensfun name of camera model
   - Lensfun name of lens make
   - Lensfun name of lens model

   All coordinates are pixel coordinates, with the top left of the image the
   origin.  The corners must be the corners of a perfect rectangle which was
   taken a picture of, e.g. a sheet of paper.  These are used for the
   perspective correction as well as the rotation, so that the edges of the
   rectangle are parellel to the image borders.

   The program returns the position and the dimensions of the rectangle in
   the output image to stdout in JSON format:

   \code{.json}
   [x₀, y₀, width, height]
   \endcode

   Here, x₀ and y₀ are the coordinates of the top left corner, and width and
   height are the dimensions of the rectangle.

   This program does not apply colour corrections such as vignetting
   correction, as those are handled by kamscan.py using flat field images.
*/
#include <Python.h>
#include <fstream>
#include <vector>
#include <iterator>
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include "lensfun/lensfun.h"

/** Class for bitmap data.

  In case of 2 bytes per channel, network byte order is assumed. */
class Image {
public:
    Image(int width, int height, int channel_size, int channels);
    Image() {};
    Image(const Image &image);
    /** Get the channel intensity at a certian coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \return raw integer value of the intensity of this channel at this
        position
    */
    int get(int x, int y, int channel);
    /** Get the channel intensity at a certian coordinate.  The coordinates are
      floats and may contain fractions.  In this case, the intensity is
      calculated using bilinear interpolation between the four pixels around
      this coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \return raw integer value of the intensity of this channel at this
        position
    */
    int get(float x, float y, int channel);
    /** Set the channel intensity at a certian coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \param value raw integer value of the intensity of this channel at this
        position
    */
    void set(int x, int y, int channel, int value);
    /** Determine the channel descriptions.  This is used by Lensfun internally
      and necessary if you want to apply colour corrections, e.g. vignetting
      correction.
      \return the components of each pixel
    */
    int components();
    /** Determine the pixel format à la Lensfun.  It is derived from
      channel_size.
      \return the pixel format as it is needed by Lensfun
     */
    lfPixelFormat pixel_format();
    int width, height; ///< width and height of the image in pixels
    int channels; ///< number of channels; may be 1 (greyscale) or 3 (RGB)
    /** the raw data (1:1 dump of the PNM content, without header)
     */
    std::vector<unsigned char> data;

private:
    friend std::istream& operator>>(std::istream &inputStream, Image &other);
    friend std::ostream& operator<<(std::ostream &outputStream, const Image &other);
    int channel_size; ///< width of one channel in bytes; may be 1 or 2
};

Image::Image(int width, int height, int channel_size, int channels) :
    width(width), height(height), channel_size(channel_size), channels(channels)
{
    data.resize(width * height * channel_size * channels);
}

Image::Image(const Image &image) :
    width(image.width), height(image.height), channel_size(image.channel_size), channels(image.channels) {
    data.resize(width * height * channel_size * channels);
}

int Image::get(int x, int y, int channel) {
    if (x < 0 || x >= width || y < 0 || y >= height)
        return 0;
    int position = channel_size * (channels * (y * width + x) + channel);
    int result = static_cast<int>(data[position]);
    if (channel_size == 2)
        result = (result << 8) + static_cast<int>(data[position + 1]);
    return result;
}

int Image::get(float x, float y, int channel) {
    float dummy;
    int x0 = static_cast<int>(x);
    int y0 = static_cast<int>(y);
    float i0 = static_cast<float>(get(x0, y0, channel));
    float i1 = static_cast<float>(get(x0 + 1, y0, channel));
    float i2 = static_cast<float>(get(x0, y0 + 1, channel));
    float i3 = static_cast<float>(get(x0 + 1, y0 + 1, channel));
    float fraction_x = std::modf(x, &dummy);
    float i01 = (1 - fraction_x) * i0 + fraction_x * i1;
    float i23 = (1 - fraction_x) * i2 + fraction_x * i3;
    float fraction_y = std::modf(y, &dummy);
    return static_cast<int>(std::round((1 - fraction_y) * i01 + fraction_y * i23));
}

void Image::set(int x, int y, int channel, int value) {
    if (x >= 0 && x < width && y >= 0 && y < height) {
        int position = channel_size * (channels * (y * width + x) + channel);
        if (channel_size == 1)
            data[position] = static_cast<unsigned char>(value);
        else if (channel_size == 2) {
            data[position] = static_cast<unsigned char>(value >> 8);
            data[position + 1] = static_cast<unsigned char>(value & 256);
        }
    }
}

int Image::components() {
    switch (channels) {
    case 1:
        return LF_CR_1(INTENSITY);
    case 3:
        return LF_CR_3(RED, GREEN, BLUE);
    default:
        throw std::runtime_error("Invalid value of 'channels'.");
    }
}

lfPixelFormat Image::pixel_format() {
    switch (channel_size) {
    case 1:
        return LF_PF_U8;
    case 2:
        return LF_PF_U16;
    default:
        throw std::runtime_error("Invalid value of 'channel_size'.");
    }
}

std::istream& operator>>(std::istream &inputStream, Image &other)
{
    std::string magic_number;
    int maximum_color_value;
    inputStream >> magic_number;
    if (magic_number == "P5")
        other.channels = 1;
    else if (magic_number == "P6")
        other.channels = 3;
    else
        throw std::runtime_error("Invalid input file.  Must start with 'P5' or 'P6'.");
    inputStream >> other.width >> other.height >> maximum_color_value;
    inputStream.get(); // skip the trailing white space
    switch (maximum_color_value) {
    case 255:
        other.channel_size = 1;
        break;
    case 65535:
        other.channel_size = 2;
        break;
    default:
        throw std::runtime_error("Invalid PPM file: Maximum color value must be 255 or 65535.");
    }
    size_t size = other.width * other.height * other.channel_size * other.channels;
    other.data.resize(size);
    inputStream.read(reinterpret_cast<char*>(other.data.data()), size);
    return inputStream;
}

std::ostream& operator<<(std::ostream &outputStream, const Image &other)
{
    outputStream << (other.channels == 3 ? "P6" : "P5") << "\n"
                 << other.width << " "
                 << other.height << "\n"
                 << (other.channel_size == 1 ? "255" : "65535") << "\n";
    outputStream.write(reinterpret_cast<const char*>(other.data.data()), other.data.size());
    return outputStream;
}

static PyObject *undistort(PyObject *self, PyObject *args) {
    const char *filename, *camera_make, *camera_model, *lens_make, *lens_model;
    float x0, y0, x1, y1, x2, y2, x3, y3;
    PyArg_ParseTuple(args, "sffffffffssss", &filename, &x0, &y0, &x1, &y1, &x2, &y2, &x3, &y3,
                     &camera_make, &camera_model, &lens_make, &lens_model);

    lfDatabase ldb;

    if (ldb.Load() != LF_NO_ERROR) {
        PyErr_SetString(PyExc_RuntimeError, "Database could not be loaded");
        return NULL;
    }

    const lfCamera *camera;
    const lfCamera **cameras = ldb.FindCamerasExt(camera_make, camera_model);
    if (cameras && !cameras[1])
        camera = cameras[0];
    else {
        std::vector<char> buffer(std::snprintf(nullptr, 0, "Cannot find unique camera in database.  %i cameras found.",
                                               (int)sizeof(cameras)));
        std::snprintf(&buffer[0], buffer.size(), "Cannot find unique camera in database.  %i cameras found.",
                      (int)sizeof(cameras));
        // FixMe: Is the second argument really copied on the other side?
        // Because buffer.data() will be free'ed after the return.
        PyErr_SetString(PyExc_RuntimeError, buffer.data());
        lf_free(cameras);
        return NULL;
    }
    lf_free(cameras);

    const lfLens *lens;
    const lfLens **lenses = ldb.FindLenses(camera, lens_make, lens_model);
    if (lenses && !lenses[1]) {
        lens = lenses[0];
    } else if (!lenses) {
        PyErr_SetString(PyExc_RuntimeError, "Cannot find lens in database");
        lf_free(lenses);
        return NULL;
    } else {
        PyErr_SetString(PyExc_RuntimeError, "Lens name ambiguous");
        lf_free(lenses);
        return NULL;
    }
    lf_free(lenses);

    Image image;
    {
        std::ifstream file(filename, std::ios::binary);
        file >> image;
    }

    lfModifier modifier(camera->CropFactor, image.width, image.height, image.pixel_format());
    lfModifier pc_coord_modifier(camera->CropFactor, image.width, image.height, image.pixel_format(), true);
    lfModifier back_modifier(camera->CropFactor, image.width, image.height, image.pixel_format(), true);
    if (!modifier.EnableDistortionCorrection(lens, 50) || !back_modifier.EnableDistortionCorrection(lens, 50) ||
        !pc_coord_modifier.EnableDistortionCorrection(lens, 50)) {
        PyErr_SetString(PyExc_RuntimeError, "Failed to activate undistortion");
        return NULL;
    }
    if (image.channels == 3)
        if (!modifier.EnableTCACorrection(lens, 50)) {
            PyErr_SetString(PyExc_RuntimeError, "Failed to activate un-TCA");
            return NULL;
        }
    std::vector<float> x, y;
    x.push_back(x0);
    y.push_back(y0);

    x.push_back(x2);
    y.push_back(y2);

    x.push_back(x1);
    y.push_back(y1);

    x.push_back(x3);
    y.push_back(y3);

    x.push_back(x0);
    y.push_back(y0);

    x.push_back(x1);
    y.push_back(y1);
    std::vector<float> x_undist, y_undist;
    for (int i = 0; i < x.size(); i++) {
        float result[2];
        pc_coord_modifier.ApplyGeometryDistortion(x[i], y[i], 1, 1, result);
        x_undist.push_back(result[0]);
        y_undist.push_back(result[1]);
    }
    if (!modifier.EnablePerspectiveCorrection(lens, 50, x_undist.data(), y_undist.data(), 6, 0) ||
        !back_modifier.EnablePerspectiveCorrection(lens, 50, x_undist.data(), y_undist.data(), 6, 0)) {
        PyErr_SetString(PyExc_RuntimeError, "Failed to activate perspective correction");
        return NULL;
    }

    std::vector<float> res(image.width * image.height * 2 * image.channels);
    if (image.channels == 3)
        modifier.ApplySubpixelGeometryDistortion(0, 0, image.width, image.height, res.data());
    else
        modifier.ApplyGeometryDistortion(0, 0, image.width, image.height, res.data());
    Image new_image = image;
    for (int x = 0; x < image.width; x++)
        for (int y = 0; y < image.height; y++) {
            int position = 2 * image.channels * (y * image.width + x);
            float source_x_R = res[position];
            float source_y_R = res[position + 1];
            new_image.set(x, y, 0, image.get(source_x_R, source_y_R, 0));
            if (image.channels == 3) {
                float source_x_G = res[position + 2];
                float source_y_G = res[position + 3];
                float source_x_B = res[position + 4];
                float source_y_B = res[position + 5];
                new_image.set(x, y, 1, image.get(source_x_G, source_y_G, 1));
                new_image.set(x, y, 2, image.get(source_x_B, source_y_B, 2));
            }
        }
    std::ofstream file(filename, std::ios::binary);
    file << new_image;

    for (int i = 0; i < 4; i++) {
        float result[2];
        back_modifier.ApplyGeometryDistortion(x[i], y[i], 1, 1, result);
        x[i] = result[0];
        y[i] = result[1];
    }

    return Py_BuildValue("ffff", std::min(x[0], x[2]), std::min(y[0], y[1]),
                         std::max(x[1], x[3]) - std::min(x[0], x[2]), std::max(y[2], y[3]) - std::min(y[0], y[1]));
}

static PyMethodDef UndistortMethods[] = {
    {"undistort",  undistort, METH_VARARGS, "Undistort PNM image data."},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef undistortmodule = {
   PyModuleDef_HEAD_INIT, "undistort", NULL, -1, UndistortMethods
};

PyMODINIT_FUNC
PyInit_undistort(void)
{
    return PyModule_Create(&undistortmodule);
}
<|endoftext|>


<commit_before>#ifndef VSMC_CXX11_FUNCTIONAL_HPP
#define VSMC_CXX11_FUNCTIONAL_HPP

#include <vsmc/internal/config.hpp>
#include <vsmc/internal/defines.hpp>

#if VSMC_HAS_CXX11LIB_FUNCTIONAL

#include <functional>
namespace vsmc { namespace cxx11 {
using std::function;
} }
#else // VSMC_HAS_CXX11LIB_FUNCTIONAL
#include <boost/function.hpp>
namespace vsmc { namespace cxx11 {
using boost::function;
} }
#endif // VSMC_HAS_CXX11LIB_FUNCTIONAL

#endif // VSMC_CXX11_FUNCTIONAL_HPP
<commit_msg>revert last commit<commit_after>#ifndef VSMC_CXX11_FUNCTIONAL_HPP
#define VSMC_CXX11_FUNCTIONAL_HPP

#include <vsmc/internal/config.hpp>

#if VSMC_HAS_CXX11LIB_FUNCTIONAL

#include <functional>
namespace vsmc { namespace cxx11 {
using std::function;
} }
#else // VSMC_HAS_CXX11LIB_FUNCTIONAL
#include <boost/function.hpp>
namespace vsmc { namespace cxx11 {
using boost::function;
} }
#endif // VSMC_HAS_CXX11LIB_FUNCTIONAL

#endif // VSMC_CXX11_FUNCTIONAL_HPP
<|endoftext|>


<commit_before>#ifndef VSMC_SMP_PARALLEL_GCD_HPP
#define VSMC_SMP_PARALLEL_GCD_HPP

#include <vsmc/internal/common.hpp>
#include <vsmc/smp/base.hpp>
#include <vsmc/utility/dispatch.hh>

namespace vsmc {

/// \brief Particle::value_type subtype
/// \ingroup GCD
template <unsigned Dim, typename T>
class StateGCD : public StateBase<Dim, T>
{
    public :

    typedef StateBase<Dim, T> state_base_type;
    typedef typename state_base_type::size_type size_type;
    typedef typename state_base_type::state_type state_type;

    explicit StateGCD (size_type N) : StateBase<Dim, T>(N) {}
}; // class StateGCD

/// \brief Sampler<T>::init_type subtype
/// \ingroup GCD
template <typename T, typename Derived>
class InitializeGCD : public InitializeBase<T, Derived>
{
    public :

    typedef InitializeBase<T, Derived> initialize_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    unsigned operator() (Particle<T> &particle, void *param)
    {
        this->initialize_param(particle, param);
        this->pre_processor(particle);
        accept_.resize(particle.size());
        work_param_ wp = {this, &particle, &accept_[0]};
        dispatch_apply_f(particle.size(),
                gcd::DispatchQueue::instance().queue(),
                (void *) &wp, work_);
        this->post_processor(particle);

        return std::accumulate(accept_.begin(), accept_.end(),
                static_cast<unsigned>(0));
    }

    protected :

    InitializeGCD () {}
    InitializeGCD (const InitializeGCD<T, Derived> &) {}
    InitializeGCD<T, Derived> &operator=
        (const InitializeGCD<T, Derived> &) {return *this;}
    ~InitializeGCD () {}

    private :

    std::vector<unsigned> accept_;

    struct work_param_
    {
        InitializeGCD<T, Derived> *const dispatcher;
        Particle<T> *const particle;
        unsigned *const accept;
    };

    static void work_ (void *wp, std::size_t i)
    {
        const work_param_ *const wptr =
            reinterpret_cast<const work_param_ *>(wp);
        wptr->accept[i] = wptr->dispatcher->initialize_state(
                SingleParticle<T>(static_cast<size_type>(i), wptr->particle));
    }
}; // class InitializeGCD

/// \brief Sampler<T>::move_type subtype
/// \ingroup GCD
template <typename T, typename Derived>
class MoveGCD : public MoveBase<T, Derived>
{
    public :

    typedef MoveBase<T, Derived> move_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    unsigned operator() (unsigned iter, Particle<T> &particle)
    {
        this->pre_processor(iter, particle);
        accept_.resize(particle.size());
        work_param_ wp = {this, &particle, &accept_[0], iter};
        dispatch_apply_f(particle.size(),
                gcd::DispatchQueue::instance().queue(),
                (void *) &wp, work_);
        this->post_processor(iter, particle);

        return std::accumulate(accept_.begin(), accept_.end(),
                static_cast<unsigned>(0));
    }

    protected :

    MoveGCD () {}
    MoveGCD (const MoveGCD<T, Derived> &) {}
    MoveGCD<T, Derived> &operator=
        (const MoveGCD<T, Derived> &) {return *this;}
    ~MoveGCD () {}

    private :

    std::vector<unsigned> accept_;

    struct work_param_
    {
        MoveGCD<T, Derived> *const dispatcher;
        Particle<T> *const particle;
        unsigned *const accept;
        unsigned iter;
    };

    static void work_ (void *wp, std::size_t i)
    {
        const work_param_ *const wptr =
            reinterpret_cast<const work_param_ *>(wp);
        wptr->accept[i] = wptr->dispatcher->move_state(wptr->iter,
                SingleParticle<T>(static_cast<size_type>(i), wptr->particle));
    }
}; // class MoveGCD

/// \brief Monitor<T>::eval_type subtype
/// \ingroup GCD
template <typename T, typename Derived>
class MonitorEvalGCD : public MonitorEvalBase<T, Derived>
{
    public :

    typedef MonitorEvalBase<T, Derived> monitor_eval_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    void operator() (unsigned iter, unsigned dim, const Particle<T> &particle,
            double *res)
    {
        this->pre_processor(iter, particle);
        work_param_ wp = {this, &particle, res, iter, dim};
        dispatch_apply_f(particle.size(),
                gcd::DispatchQueue::instance().queue(),
                (void *) &wp, work_);
        this->post_processor(iter, particle);
    }

    protected :

    MonitorEvalGCD () {}
    MonitorEvalGCD (const MonitorEvalGCD<T, Derived> &) {}
    MonitorEvalGCD<T, Derived> &operator=
        (const MonitorEvalGCD<T, Derived> &) {return *this;}
    ~MonitorEvalGCD () {}

    private :

    struct work_param_
    {
        MonitorEvalGCD<T, Derived> *const dispatcher;
        const Particle<T> *const particle;
        double *const res;
        unsigned iter;
        unsigned dim;
    };

    static void work_ (void *wp, std::size_t i)
    {
        const work_param_ *const wptr =
            reinterpret_cast<const work_param_ *>(wp);
        wptr->dispatcher->monitor_state(wptr->iter, wptr->dim,
                ConstSingleParticle<T>(
                    static_cast<size_type>(i), wptr->particle),
                wptr->res + i * wptr->dim);
    }
}; // class MonitorEvalGCD

/// \brief Path<T>::eval_type subtype
/// \ingroup GCD
template <typename T, typename Derived>
class PathEvalGCD : public PathEvalBase<T, Derived>
{
    public :

    typedef PathEvalBase<T, Derived> path_eval_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    double operator() (unsigned iter, const Particle<T> &particle, double *res)
    {
        this->pre_processor(iter, particle);
        work_param_ wp = {this, &particle, res, iter};
        dispatch_apply_f(particle.size(),
                gcd::DispatchQueue::instance().queue(),
                (void *) &wp, work_);
        this->post_processor(iter, particle);

        return this->path_width(iter, particle);
    }

    protected :

    PathEvalGCD () {}
    PathEvalGCD (const PathEvalGCD<T, Derived> &) {}
    PathEvalGCD<T, Derived> &operator=
        (const PathEvalGCD<T, Derived> &) {return *this;}
    ~PathEvalGCD () {}

    private :

    struct work_param_
    {
        PathEvalGCD<T, Derived> *const dispatcher;
        const Particle<T> *const particle;
        double *const res;
        unsigned iter;
    };

    static void work_ (void *wp, std::size_t i)
    {
        const work_param_ *const wptr =
            reinterpret_cast<const work_param_ *>(wp);
        wptr->res[i] = wptr->dispatcher->path_state(wptr->iter,
                ConstSingleParticle<T>(
                    static_cast<size_type>(i), wptr->particle));
    }
}; // class PathEvalGCD

}

#endif // VSMC_SMP_PARALLEL_GCD_HPP
<commit_msg>fix typo<commit_after>#ifndef VSMC_SMP_PARALLEL_GCD_HPP
#define VSMC_SMP_PARALLEL_GCD_HPP

#include <vsmc/internal/common.hpp>
#include <vsmc/smp/base.hpp>
#include <vsmc/utility/dispatch.hpp>

namespace vsmc {

/// \brief Particle::value_type subtype
/// \ingroup GCD
template <unsigned Dim, typename T>
class StateGCD : public StateBase<Dim, T>
{
    public :

    typedef StateBase<Dim, T> state_base_type;
    typedef typename state_base_type::size_type size_type;
    typedef typename state_base_type::state_type state_type;

    explicit StateGCD (size_type N) : StateBase<Dim, T>(N) {}
}; // class StateGCD

/// \brief Sampler<T>::init_type subtype
/// \ingroup GCD
template <typename T, typename Derived>
class InitializeGCD : public InitializeBase<T, Derived>
{
    public :

    typedef InitializeBase<T, Derived> initialize_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    unsigned operator() (Particle<T> &particle, void *param)
    {
        this->initialize_param(particle, param);
        this->pre_processor(particle);
        accept_.resize(particle.size());
        work_param_ wp = {this, &particle, &accept_[0]};
        dispatch_apply_f(particle.size(),
                gcd::DispatchQueue::instance().queue(),
                (void *) &wp, work_);
        this->post_processor(particle);

        return std::accumulate(accept_.begin(), accept_.end(),
                static_cast<unsigned>(0));
    }

    protected :

    InitializeGCD () {}
    InitializeGCD (const InitializeGCD<T, Derived> &) {}
    InitializeGCD<T, Derived> &operator=
        (const InitializeGCD<T, Derived> &) {return *this;}
    ~InitializeGCD () {}

    private :

    std::vector<unsigned> accept_;

    struct work_param_
    {
        InitializeGCD<T, Derived> *const dispatcher;
        Particle<T> *const particle;
        unsigned *const accept;
    };

    static void work_ (void *wp, std::size_t i)
    {
        const work_param_ *const wptr =
            reinterpret_cast<const work_param_ *>(wp);
        wptr->accept[i] = wptr->dispatcher->initialize_state(
                SingleParticle<T>(static_cast<size_type>(i), wptr->particle));
    }
}; // class InitializeGCD

/// \brief Sampler<T>::move_type subtype
/// \ingroup GCD
template <typename T, typename Derived>
class MoveGCD : public MoveBase<T, Derived>
{
    public :

    typedef MoveBase<T, Derived> move_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    unsigned operator() (unsigned iter, Particle<T> &particle)
    {
        this->pre_processor(iter, particle);
        accept_.resize(particle.size());
        work_param_ wp = {this, &particle, &accept_[0], iter};
        dispatch_apply_f(particle.size(),
                gcd::DispatchQueue::instance().queue(),
                (void *) &wp, work_);
        this->post_processor(iter, particle);

        return std::accumulate(accept_.begin(), accept_.end(),
                static_cast<unsigned>(0));
    }

    protected :

    MoveGCD () {}
    MoveGCD (const MoveGCD<T, Derived> &) {}
    MoveGCD<T, Derived> &operator=
        (const MoveGCD<T, Derived> &) {return *this;}
    ~MoveGCD () {}

    private :

    std::vector<unsigned> accept_;

    struct work_param_
    {
        MoveGCD<T, Derived> *const dispatcher;
        Particle<T> *const particle;
        unsigned *const accept;
        unsigned iter;
    };

    static void work_ (void *wp, std::size_t i)
    {
        const work_param_ *const wptr =
            reinterpret_cast<const work_param_ *>(wp);
        wptr->accept[i] = wptr->dispatcher->move_state(wptr->iter,
                SingleParticle<T>(static_cast<size_type>(i), wptr->particle));
    }
}; // class MoveGCD

/// \brief Monitor<T>::eval_type subtype
/// \ingroup GCD
template <typename T, typename Derived>
class MonitorEvalGCD : public MonitorEvalBase<T, Derived>
{
    public :

    typedef MonitorEvalBase<T, Derived> monitor_eval_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    void operator() (unsigned iter, unsigned dim, const Particle<T> &particle,
            double *res)
    {
        this->pre_processor(iter, particle);
        work_param_ wp = {this, &particle, res, iter, dim};
        dispatch_apply_f(particle.size(),
                gcd::DispatchQueue::instance().queue(),
                (void *) &wp, work_);
        this->post_processor(iter, particle);
    }

    protected :

    MonitorEvalGCD () {}
    MonitorEvalGCD (const MonitorEvalGCD<T, Derived> &) {}
    MonitorEvalGCD<T, Derived> &operator=
        (const MonitorEvalGCD<T, Derived> &) {return *this;}
    ~MonitorEvalGCD () {}

    private :

    struct work_param_
    {
        MonitorEvalGCD<T, Derived> *const dispatcher;
        const Particle<T> *const particle;
        double *const res;
        unsigned iter;
        unsigned dim;
    };

    static void work_ (void *wp, std::size_t i)
    {
        const work_param_ *const wptr =
            reinterpret_cast<const work_param_ *>(wp);
        wptr->dispatcher->monitor_state(wptr->iter, wptr->dim,
                ConstSingleParticle<T>(
                    static_cast<size_type>(i), wptr->particle),
                wptr->res + i * wptr->dim);
    }
}; // class MonitorEvalGCD

/// \brief Path<T>::eval_type subtype
/// \ingroup GCD
template <typename T, typename Derived>
class PathEvalGCD : public PathEvalBase<T, Derived>
{
    public :

    typedef PathEvalBase<T, Derived> path_eval_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    double operator() (unsigned iter, const Particle<T> &particle, double *res)
    {
        this->pre_processor(iter, particle);
        work_param_ wp = {this, &particle, res, iter};
        dispatch_apply_f(particle.size(),
                gcd::DispatchQueue::instance().queue(),
                (void *) &wp, work_);
        this->post_processor(iter, particle);

        return this->path_width(iter, particle);
    }

    protected :

    PathEvalGCD () {}
    PathEvalGCD (const PathEvalGCD<T, Derived> &) {}
    PathEvalGCD<T, Derived> &operator=
        (const PathEvalGCD<T, Derived> &) {return *this;}
    ~PathEvalGCD () {}

    private :

    struct work_param_
    {
        PathEvalGCD<T, Derived> *const dispatcher;
        const Particle<T> *const particle;
        double *const res;
        unsigned iter;
    };

    static void work_ (void *wp, std::size_t i)
    {
        const work_param_ *const wptr =
            reinterpret_cast<const work_param_ *>(wp);
        wptr->res[i] = wptr->dispatcher->path_state(wptr->iter,
                ConstSingleParticle<T>(
                    static_cast<size_type>(i), wptr->particle));
    }
}; // class PathEvalGCD

}

#endif // VSMC_SMP_PARALLEL_GCD_HPP
<|endoftext|>


<commit_before>#ifndef VSMC_SMP_PARALLEL_TBB_HPP
#define VSMC_SMP_PARALLEL_TBB_HPP

#if defined(__clang__) && !defined(_LIBCPP_VERSION) && (__GLIBCXX__ < 20100429)
#ifndef TBB_USE_CAPTURED_EXCEPTION
#define TBB_USE_CAPTURED_EXCEPTION 1
#endif
#endif // __clang__

#include <vsmc/smp/base.hpp>
#include <tbb/tbb.h>

namespace vsmc {

/// \brief Particle::value_type subtype
/// \ingroup TBB
template <std::size_t Dim, typename T>
class StateTBB : public StateBase<Dim, T>
{
    public :

    typedef StateBase<Dim, T> state_base_type;
    typedef typename state_base_type::size_type size_type;
    typedef typename state_base_type::state_type state_type;

    explicit StateTBB (size_type N) : StateBase<Dim, T>(N) {}

    template <typename IntType>
    void copy (size_type N, const IntType *copy_from)
    {
        VSMC_RUNTIME_ASSERT_STATE_COPY_SIZE_MISMATCH(TBB);

        tbb::parallel_for(tbb::blocked_range<size_type>(0, this->size()),
                copy_work_<IntType>(this, copy_from));
    }

    private :

    template <typename IntType>
    class copy_work_
    {
        public :

        copy_work_ (StateTBB<Dim, T> *state, const IntType *copy_from) :
            state_(state), copy_from_(copy_from) {}

        void operator() (const tbb::blocked_range<size_type> &range) const
        {
            for (size_type to = range.begin(); to != range.end(); ++to)
                state_->copy_particle(copy_from_[to], to);
        }

        private :

        StateTBB<Dim, T> *const state_;
        const IntType *const copy_from_;
    }; // class copy_work_
}; // class StateTBB

/// \brief Sampler<T>::init_type subtype
/// \ingroup TBB
template <typename T, typename Derived>
class InitializeTBB : public InitializeBase<T, Derived>
{
    public :

    typedef InitializeBase<T, Derived> initialize_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    std::size_t operator() (Particle<T> &particle, void *param)
    {
        this->initialize_param(particle, param);
        this->pre_processor(particle);
        work_ work(this, &particle);
        tbb::parallel_reduce(tbb::blocked_range<size_type>(
                    0, particle.size()), work);
        this->post_processor(particle);

        return work.accept();
    }

    protected :

    InitializeTBB () {}
    InitializeTBB (const InitializeTBB<T, Derived> &) {}
    InitializeTBB<T, Derived> &operator=
        (const InitializeTBB<T, Derived> &) {return *this;}
    ~InitializeTBB () {}

    private :

    class work_
    {
        public :

        work_ (InitializeTBB<T, Derived> *init,
                Particle<T> *particle) :
            init_(init), particle_(particle), accept_(0) {}

        work_ (const work_ &other, tbb::split) :
            init_(other.init_), particle_(other.particle_), accept_(0) {}

        void operator() (const tbb::blocked_range<size_type> &range)
        {
            std::size_t acc = accept_;
            for (size_type i = range.begin(); i != range.end(); ++i) {
                acc += init_->initialize_state(
                        SingleParticle<T>(i, particle_));
            }
            accept_ = acc;
        }

        void join (const work_ &other)
        {
            accept_ += other.accept_;
        }

        std::size_t accept () const
        {
            return accept_;
        }

        private :

        InitializeTBB<T, Derived> *const init_;
        Particle<T> *const particle_;
        std::size_t accept_;
    }; // class work_
}; // class InitializeTBB

/// \brief Sampler<T>::move_type subtype
/// \ingroup TBB
template <typename T, typename Derived>
class MoveTBB : public MoveBase<T, Derived>
{
    public :

    typedef MoveBase<T, Derived> move_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    std::size_t operator() (std::size_t iter, Particle<T> &particle)
    {
        this->pre_processor(iter, particle);
        work_ work(this, iter, &particle);
        tbb::parallel_reduce(tbb::blocked_range<size_type>(
                    0, particle.size()), work);
        this->post_processor(iter, particle);

        return work.accept();
    }

    protected :

    MoveTBB () {}
    MoveTBB (const MoveTBB<T, Derived> &) {}
    MoveTBB<T, Derived> &operator=
        (const MoveTBB<T, Derived> &) {return *this;}
    ~MoveTBB () {}

    private :

    class work_
    {
        public :

        work_ (MoveTBB<T, Derived> *move, std::size_t iter,
                Particle<T> *particle):
            move_(move), iter_(iter), particle_(particle), accept_(0) {}

        work_ (const work_ &other, tbb::split) :
            move_(other.move_), iter_(other.iter_),
            particle_(other.particle_), accept_(0) {}

        void operator() (const tbb::blocked_range<size_type> &range)
        {
            std::size_t acc = accept_;
            for (size_type i = range.begin(); i != range.end(); ++i) {
                acc += move_->move_state(iter_,
                        SingleParticle<T>(i, particle_));
            }
            accept_ = acc;
        }

        void join (const work_ &other)
        {
            accept_ += other.accept_;
        }

        std::size_t accept () const
        {
            return accept_;
        }

        private :

        MoveTBB<T, Derived> *const move_;
        const std::size_t iter_;
        Particle<T> *const particle_;
        std::size_t accept_;
    }; // class work_
}; // class MoveTBB

/// \brief Monitor<T>::eval_type subtype
/// \ingroup TBB
template <typename T, typename Derived>
class MonitorEvalTBB : public MonitorEvalBase<T, Derived>
{
    public :

    typedef MonitorEvalBase<T, Derived> monitor_eval_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    void operator() (std::size_t iter, std::size_t dim,
            const Particle<T> &particle, double *res)
    {
        this->pre_processor(iter, particle);
        tbb::parallel_for(tbb::blocked_range<size_type>(0, particle.size()),
                work_(this, iter, dim, &particle, res));
        this->post_processor(iter, particle);
    }

    protected :

    MonitorEvalTBB () {}
    MonitorEvalTBB (const MonitorEvalTBB<T, Derived> &) {}
    MonitorEvalTBB<T, Derived> &operator=
        (const MonitorEvalTBB<T, Derived> &) {return *this;}
    ~MonitorEvalTBB () {}

    private :

    class work_
    {
        public :

        work_ (MonitorEvalTBB<T, Derived> *monitor,
                std::size_t iter, std::size_t dim,
                const Particle<T> *particle, double *res) :
            monitor_(monitor), particle_(particle), res_(res),
            iter_(iter), dim_(dim) {}

        void operator() (const tbb::blocked_range<size_type> &range) const
        {
            for (size_type i = range.begin(); i != range.end(); ++i) {
                monitor_->monitor_state(iter_, dim_,
                        ConstSingleParticle<T>(i, particle_), res_ + i * dim_);
            }
        }

        private :

        MonitorEvalTBB<T, Derived> *const monitor_;
        const Particle<T> *const particle_;
        double *const res_;
        const std::size_t iter_;
        const std::size_t dim_;
    }; // class work_
}; // class MonitorEvalTBB

/// \brief Path<T>::eval_type subtype
/// \ingroup TBB
template <typename T, typename Derived>
class PathEvalTBB : public PathEvalBase<T, Derived>
{
    public :

    typedef PathEvalBase<T, Derived> path_eval_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    double operator() (std::size_t iter, const Particle<T> &particle,
            double *res)
    {
        this->pre_processor(iter, particle);
        tbb::parallel_for(tbb::blocked_range<size_type>(0, particle.size()),
                work_(this, iter, &particle, res));
        this->post_processor(iter, particle);

        return this->path_grid(iter, particle);
    }

    protected :

    PathEvalTBB () {}
    PathEvalTBB (const PathEvalTBB<T, Derived> &) {}
    PathEvalTBB<T, Derived> &operator=
        (const PathEvalTBB<T, Derived> &) {return *this;}
    ~PathEvalTBB () {}

    private :

    class work_
    {
        public :

        work_ (PathEvalTBB<T, Derived> *path, std::size_t iter,
                const Particle<T> *particle, double *res) :
            path_(path), particle_(particle), res_(res), iter_(iter) {}

        void operator() (const tbb::blocked_range<size_type> &range) const
        {
            for (size_type i = range.begin(); i != range.end(); ++i) {
                res_[i] = path_->path_state(iter_,
                        ConstSingleParticle<T>(i, particle_));
            }
        }

        private :

        PathEvalTBB<T, Derived> *const path_;
        const Particle<T> *const particle_;
        double *const res_;
        const std::size_t iter_;
    }; // class work_
}; // PathEvalTBB

} // namespace vsmc

#endif // VSMC_SMP_PARALLEL_TBB_HPP
<commit_msg>reorder tbb work item layout<commit_after>#ifndef VSMC_SMP_PARALLEL_TBB_HPP
#define VSMC_SMP_PARALLEL_TBB_HPP

#if defined(__clang__) && !defined(_LIBCPP_VERSION) && (__GLIBCXX__ < 20100429)
#ifndef TBB_USE_CAPTURED_EXCEPTION
#define TBB_USE_CAPTURED_EXCEPTION 1
#endif
#endif // __clang__

#include <vsmc/smp/base.hpp>
#include <tbb/tbb.h>

namespace vsmc {

/// \brief Particle::value_type subtype
/// \ingroup TBB
template <std::size_t Dim, typename T>
class StateTBB : public StateBase<Dim, T>
{
    public :

    typedef StateBase<Dim, T> state_base_type;
    typedef typename state_base_type::size_type size_type;
    typedef typename state_base_type::state_type state_type;

    explicit StateTBB (size_type N) : StateBase<Dim, T>(N) {}

    template <typename IntType>
    void copy (size_type N, const IntType *copy_from)
    {
        VSMC_RUNTIME_ASSERT_STATE_COPY_SIZE_MISMATCH(TBB);

        tbb::parallel_for(tbb::blocked_range<size_type>(0, this->size()),
                copy_work_<IntType>(this, copy_from));
    }

    private :

    template <typename IntType>
    class copy_work_
    {
        public :

        copy_work_ (StateTBB<Dim, T> *state, const IntType *copy_from) :
            state_(state), copy_from_(copy_from) {}

        void operator() (const tbb::blocked_range<size_type> &range) const
        {
            for (size_type to = range.begin(); to != range.end(); ++to)
                state_->copy_particle(copy_from_[to], to);
        }

        private :

        StateTBB<Dim, T> *const state_;
        const IntType *const copy_from_;
    }; // class copy_work_
}; // class StateTBB

/// \brief Sampler<T>::init_type subtype
/// \ingroup TBB
template <typename T, typename Derived>
class InitializeTBB : public InitializeBase<T, Derived>
{
    public :

    typedef InitializeBase<T, Derived> initialize_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    std::size_t operator() (Particle<T> &particle, void *param)
    {
        this->initialize_param(particle, param);
        this->pre_processor(particle);
        work_ work(this, &particle);
        tbb::parallel_reduce(tbb::blocked_range<size_type>(
                    0, particle.size()), work);
        this->post_processor(particle);

        return work.accept();
    }

    protected :

    InitializeTBB () {}
    InitializeTBB (const InitializeTBB<T, Derived> &) {}
    InitializeTBB<T, Derived> &operator=
        (const InitializeTBB<T, Derived> &) {return *this;}
    ~InitializeTBB () {}

    private :

    class work_
    {
        public :

        work_ (InitializeTBB<T, Derived> *init,
                Particle<T> *particle) :
            init_(init), particle_(particle), accept_(0) {}

        work_ (const work_ &other, tbb::split) :
            init_(other.init_), particle_(other.particle_), accept_(0) {}

        void operator() (const tbb::blocked_range<size_type> &range)
        {
            std::size_t acc = accept_;
            for (size_type i = range.begin(); i != range.end(); ++i) {
                acc += init_->initialize_state(
                        SingleParticle<T>(i, particle_));
            }
            accept_ = acc;
        }

        void join (const work_ &other)
        {
            accept_ += other.accept_;
        }

        std::size_t accept () const
        {
            return accept_;
        }

        private :

        InitializeTBB<T, Derived> *const init_;
        Particle<T> *const particle_;
        std::size_t accept_;
    }; // class work_
}; // class InitializeTBB

/// \brief Sampler<T>::move_type subtype
/// \ingroup TBB
template <typename T, typename Derived>
class MoveTBB : public MoveBase<T, Derived>
{
    public :

    typedef MoveBase<T, Derived> move_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    std::size_t operator() (std::size_t iter, Particle<T> &particle)
    {
        this->pre_processor(iter, particle);
        work_ work(this, iter, &particle);
        tbb::parallel_reduce(tbb::blocked_range<size_type>(
                    0, particle.size()), work);
        this->post_processor(iter, particle);

        return work.accept();
    }

    protected :

    MoveTBB () {}
    MoveTBB (const MoveTBB<T, Derived> &) {}
    MoveTBB<T, Derived> &operator=
        (const MoveTBB<T, Derived> &) {return *this;}
    ~MoveTBB () {}

    private :

    class work_
    {
        public :

        work_ (MoveTBB<T, Derived> *move, std::size_t iter,
                Particle<T> *particle):
            move_(move), iter_(iter), particle_(particle), accept_(0) {}

        work_ (const work_ &other, tbb::split) :
            move_(other.move_), iter_(other.iter_),
            particle_(other.particle_), accept_(0) {}

        void operator() (const tbb::blocked_range<size_type> &range)
        {
            std::size_t acc = accept_;
            for (size_type i = range.begin(); i != range.end(); ++i) {
                acc += move_->move_state(iter_,
                        SingleParticle<T>(i, particle_));
            }
            accept_ = acc;
        }

        void join (const work_ &other)
        {
            accept_ += other.accept_;
        }

        std::size_t accept () const
        {
            return accept_;
        }

        private :

        MoveTBB<T, Derived> *const move_;
        const std::size_t iter_;
        Particle<T> *const particle_;
        std::size_t accept_;
    }; // class work_
}; // class MoveTBB

/// \brief Monitor<T>::eval_type subtype
/// \ingroup TBB
template <typename T, typename Derived>
class MonitorEvalTBB : public MonitorEvalBase<T, Derived>
{
    public :

    typedef MonitorEvalBase<T, Derived> monitor_eval_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    void operator() (std::size_t iter, std::size_t dim,
            const Particle<T> &particle, double *res)
    {
        this->pre_processor(iter, particle);
        tbb::parallel_for(tbb::blocked_range<size_type>(0, particle.size()),
                work_(this, iter, dim, &particle, res));
        this->post_processor(iter, particle);
    }

    protected :

    MonitorEvalTBB () {}
    MonitorEvalTBB (const MonitorEvalTBB<T, Derived> &) {}
    MonitorEvalTBB<T, Derived> &operator=
        (const MonitorEvalTBB<T, Derived> &) {return *this;}
    ~MonitorEvalTBB () {}

    private :

    class work_
    {
        public :

        work_ (MonitorEvalTBB<T, Derived> *monitor,
                std::size_t iter, std::size_t dim,
                const Particle<T> *particle, double *res) :
            monitor_(monitor), iter_(iter), dim_(dim),
            particle_(particle), res_(res) {}

        void operator() (const tbb::blocked_range<size_type> &range) const
        {
            for (size_type i = range.begin(); i != range.end(); ++i) {
                monitor_->monitor_state(iter_, dim_,
                        ConstSingleParticle<T>(i, particle_), res_ + i * dim_);
            }
        }

        private :

        MonitorEvalTBB<T, Derived> *const monitor_;
        const std::size_t iter_;
        const std::size_t dim_;
        const Particle<T> *const particle_;
        double *const res_;
    }; // class work_
}; // class MonitorEvalTBB

/// \brief Path<T>::eval_type subtype
/// \ingroup TBB
template <typename T, typename Derived>
class PathEvalTBB : public PathEvalBase<T, Derived>
{
    public :

    typedef PathEvalBase<T, Derived> path_eval_base_type;
    typedef typename Particle<T>::size_type size_type;
    typedef T value_type;

    double operator() (std::size_t iter, const Particle<T> &particle,
            double *res)
    {
        this->pre_processor(iter, particle);
        tbb::parallel_for(tbb::blocked_range<size_type>(0, particle.size()),
                work_(this, iter, &particle, res));
        this->post_processor(iter, particle);

        return this->path_grid(iter, particle);
    }

    protected :

    PathEvalTBB () {}
    PathEvalTBB (const PathEvalTBB<T, Derived> &) {}
    PathEvalTBB<T, Derived> &operator=
        (const PathEvalTBB<T, Derived> &) {return *this;}
    ~PathEvalTBB () {}

    private :

    class work_
    {
        public :

        work_ (PathEvalTBB<T, Derived> *path, std::size_t iter,
                const Particle<T> *particle, double *res) :
            path_(path), iter_(iter), particle_(particle), res_(res) {}

        void operator() (const tbb::blocked_range<size_type> &range) const
        {
            for (size_type i = range.begin(); i != range.end(); ++i) {
                res_[i] = path_->path_state(iter_,
                        ConstSingleParticle<T>(i, particle_));
            }
        }

        private :

        PathEvalTBB<T, Derived> *const path_;
        const std::size_t iter_;
        const Particle<T> *const particle_;
        double *const res_;
    }; // class work_
}; // PathEvalTBB

} // namespace vsmc

#endif // VSMC_SMP_PARALLEL_TBB_HPP
<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) 2017, Sylvain Corlay and Johan Mabille                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XWIDGETS_MATERIALIZE_HPP
#define XWIDGETS_MATERIALIZE_HPP

#include <utility>

namespace xw
{
    /****************************
     * xmaterialize declaration *
     ****************************/

    template <template <class> class B, class... P>
    class xmaterialize final : public B<xmaterialize<B, P...>>
    {
    public:

        using self_type = xmaterialize<B, P...>;
        using base_type = B<self_type>;

        template <class... A>
        xmaterialize(A&&...);
        ~xmaterialize();

        xmaterialize(const xmaterialize&);
        xmaterialize& operator=(const xmaterialize&);

        xmaterialize(xmaterialize&&);
        xmaterialize& operator=(xmaterialize&&);
    };

    /**************************
     * xgenerator declaration *
     **************************/

    template <template <class> class B, class... P>
    class xgenerator final : public B<xgenerator<B, P...>>
    {
    public:

        using self_type = xgenerator<B, P...>;
        using base_type = B<self_type>;

        template <class... A>
        xgenerator(A&&...);

        xgenerator(const xgenerator&);
        xgenerator& operator=(const xgenerator&);

        xgenerator(xgenerator&&);
        xgenerator& operator=(xgenerator&&);

        xmaterialize<B, P...> finalize() &&;
    };

    /******************
     * xconcrete_type *
     ******************/

    template <class D>
    struct xconcrete_type
    {
        using type = D;
    };

    template <template <class> class B, class... P>
    struct xconcrete_type<xgenerator<B, P...>>
    {
        using type = xmaterialize<B, P...>;
    };

    template <class D>
    using xconcrete_type_t = typename xconcrete_type<D>::type;

    /*******************************
     * xmaterialize implementation *
     *******************************/

    template <template <class> class B, class... P>
    template <class... A>
    inline xmaterialize<B, P...>::xmaterialize(A&&... args)
        : base_type(std::forward<A>(args)...)
    {
        this->open();
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>::~xmaterialize()
    {
        if (!this->moved_from())
        {
            this->close();
        }
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>::xmaterialize(const xmaterialize& rhs)
        : base_type(rhs)
    {
        this->open();
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>& xmaterialize<B, P...>::operator=(const xmaterialize& rhs)
    {
        this->close();
        base_type::operator=(rhs);
        this->open();
        return *this;
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>::xmaterialize(xmaterialize&&) = default;

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>& xmaterialize<B, P...>::operator=(xmaterialize&& rhs) = default;

    /*****************************
     * xgenerator implementation *
     *****************************/

    template <template <class> class B, class... P>
    template <class... A>
    inline xgenerator<B, P...>::xgenerator(A&&... args)
        : base_type(std::forward<A>(args)...)
    {
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...> xgenerator<B, P...>::finalize() &&
    {
        return reinterpret_cast<typename xmaterialize<B, P...>::base_type&&>(*this);
    }

    template <template <class> class B, class... P>
    inline xgenerator<B, P...>::xgenerator(const xgenerator&) = default;

    template <template <class> class B, class... P>
    inline xgenerator<B, P...>& xgenerator<B, P...>::operator=(const xgenerator&) = default;

    template <template <class> class B, class... P>
    inline xgenerator<B, P...>::xgenerator(xgenerator&&) = default;

    template <template <class> class B, class... P>
    inline xgenerator<B, P...>& xgenerator<B, P...>::operator=(xgenerator&&) = default;
}

#include "xeus/xjson.hpp"
#include "xwidgets_config.hpp"

namespace xw
{
    /***********************************************************
     * Specialization of cling::printValue for Jupyter Widgets *
     ***********************************************************/

    template <template <class> class B, class... P>
    xeus::xjson mime_bundle_repr(const xmaterialize<B, P...>* val)
    {
        xeus::xjson mime_bundle;

        // application/vnd.jupyter.widget-view+json
        xeus::xjson widgets_json;
        widgets_json["version_major"] = XWIDGETS_PROTOCOL_VERSION_MAJOR;
        widgets_json["version_minor"] = XWIDGETS_PROTOCOL_VERSION_MINOR;
        widgets_json["model_id"] = val->id();
        mime_bundle["application/vnd.jupyter.widget-view+json"] = std::move(widgets_json);

        // text/plain
        mime_bundle["text/plain"] = "A Jupyter widget";
        return mime_bundle;
    }
}

#endif
<commit_msg>Update to xeus-cling 0.2.1<commit_after>/***************************************************************************
* Copyright (c) 2017, Sylvain Corlay and Johan Mabille                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XWIDGETS_MATERIALIZE_HPP
#define XWIDGETS_MATERIALIZE_HPP

#include <utility>

namespace xw
{
    /****************************
     * xmaterialize declaration *
     ****************************/

    template <template <class> class B, class... P>
    class xmaterialize final : public B<xmaterialize<B, P...>>
    {
    public:

        using self_type = xmaterialize<B, P...>;
        using base_type = B<self_type>;

        template <class... A>
        xmaterialize(A&&...);
        ~xmaterialize();

        xmaterialize(const xmaterialize&);
        xmaterialize& operator=(const xmaterialize&);

        xmaterialize(xmaterialize&&);
        xmaterialize& operator=(xmaterialize&&);
    };

    /**************************
     * xgenerator declaration *
     **************************/

    template <template <class> class B, class... P>
    class xgenerator final : public B<xgenerator<B, P...>>
    {
    public:

        using self_type = xgenerator<B, P...>;
        using base_type = B<self_type>;

        template <class... A>
        xgenerator(A&&...);

        xgenerator(const xgenerator&);
        xgenerator& operator=(const xgenerator&);

        xgenerator(xgenerator&&);
        xgenerator& operator=(xgenerator&&);

        xmaterialize<B, P...> finalize() &&;
    };

    /******************
     * xconcrete_type *
     ******************/

    template <class D>
    struct xconcrete_type
    {
        using type = D;
    };

    template <template <class> class B, class... P>
    struct xconcrete_type<xgenerator<B, P...>>
    {
        using type = xmaterialize<B, P...>;
    };

    template <class D>
    using xconcrete_type_t = typename xconcrete_type<D>::type;

    /*******************************
     * xmaterialize implementation *
     *******************************/

    template <template <class> class B, class... P>
    template <class... A>
    inline xmaterialize<B, P...>::xmaterialize(A&&... args)
        : base_type(std::forward<A>(args)...)
    {
        this->open();
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>::~xmaterialize()
    {
        if (!this->moved_from())
        {
            this->close();
        }
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>::xmaterialize(const xmaterialize& rhs)
        : base_type(rhs)
    {
        this->open();
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>& xmaterialize<B, P...>::operator=(const xmaterialize& rhs)
    {
        this->close();
        base_type::operator=(rhs);
        this->open();
        return *this;
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>::xmaterialize(xmaterialize&&) = default;

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...>& xmaterialize<B, P...>::operator=(xmaterialize&& rhs) = default;

    /*****************************
     * xgenerator implementation *
     *****************************/

    template <template <class> class B, class... P>
    template <class... A>
    inline xgenerator<B, P...>::xgenerator(A&&... args)
        : base_type(std::forward<A>(args)...)
    {
    }

    template <template <class> class B, class... P>
    inline xmaterialize<B, P...> xgenerator<B, P...>::finalize() &&
    {
        return reinterpret_cast<typename xmaterialize<B, P...>::base_type&&>(*this);
    }

    template <template <class> class B, class... P>
    inline xgenerator<B, P...>::xgenerator(const xgenerator&) = default;

    template <template <class> class B, class... P>
    inline xgenerator<B, P...>& xgenerator<B, P...>::operator=(const xgenerator&) = default;

    template <template <class> class B, class... P>
    inline xgenerator<B, P...>::xgenerator(xgenerator&&) = default;

    template <template <class> class B, class... P>
    inline xgenerator<B, P...>& xgenerator<B, P...>::operator=(xgenerator&&) = default;
}

#include "xeus/xjson.hpp"
#include "xwidgets_config.hpp"

namespace xw
{
    /***********************************************************
     * Specialization of cling::printValue for Jupyter Widgets *
     ***********************************************************/

    template <template <class> class B, class... P>
    xeus::xjson mime_bundle_repr(const xmaterialize<B, P...>& val)
    {
        xeus::xjson mime_bundle;

        // application/vnd.jupyter.widget-view+json
        xeus::xjson widgets_json;
        widgets_json["version_major"] = XWIDGETS_PROTOCOL_VERSION_MAJOR;
        widgets_json["version_minor"] = XWIDGETS_PROTOCOL_VERSION_MINOR;
        widgets_json["model_id"] = val.id();
        mime_bundle["application/vnd.jupyter.widget-view+json"] = std::move(widgets_json);

        // text/plain
        mime_bundle["text/plain"] = "A Jupyter widget";
        return mime_bundle;
    }
}

#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "texture_bank.h"

#include "asdf_multiplat/data/gl_resources.h"
#include "asdf_multiplat/utilities/utilities.h"
#include "asdf_multiplat/utilities/cjson_utils.hpp"

using namespace std;

namespace asdf
{
    using namespace util;

namespace hexmap {
namespace data
{

    texture_bank_t::texture_bank_t()
    : atlas_texture("hex texture atlas", nullptr, hex_atlas_dim, hex_atlas_dim)
    {
        ASSERT(!CheckGLError(), "GL Error Before Initializing texture_bank_t");

        {
            GL_State->bind(atlas_fbo);
            glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, atlas_texture.texture_id, 0);
            GLenum draw_buffers = GL_COLOR_ATTACHMENT0;
            glDrawBuffers(1, &draw_buffers);

            ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "GL Error creating texture bank framebuffer");
            GL_State->unbind_fbo();
        }

        auto dir = find_folder("data");
        ASSERT(dir.length() > 0, "Could not find data folder");

        auto imported_textures_json_filepath = dir + "/" + string(imported_textures_json_filename);

        std::string json_str = read_text_file(imported_textures_json_filepath);
        cJSON* root = cJSON_Parse(json_str.c_str());
        ASSERT(root, "Error loading imported textures json file");

        vector<char*> textures;
        CJSON_GET_STR_VECTOR(textures);

        for(auto const& filepath : textures)
        {
            if(is_file(filepath))
            {
                add_texture(filepath);
            }
            else
            {
                LOG("Texture not found at %s", filepath);
            }
        }

        cJSON_Delete(root);

        ASSERT(!CheckGLError(), "GL Error Initializing texture_bank_t");
    }

    void texture_bank_t::add_texture(std::string const& filepath)
    {
        ASSERT(is_file(filepath), "File not found %s", filepath.c_str());
        texture_t new_texture(filepath, SOIL_LOAD_RGBA); //force RGBA, since that's what the atlas uses. Might not be neccesary now that I'm rendering to a framebuffer

        //texture_t new_texture("test", nullptr, 128, 128);

        //ASSERT(new_texture.format == atlas_texture.format, "Color format of texture must match the atlas (GL_RGBA)   %s", filepath.c_str());
        //ASSERT(new_texture.types[0] == atlas_texture.types[0], "");

        int dest_loc_x = (saved_textures.size() % max_saved_textures_1d) * saved_texture_dim;
        int dest_loc_y = (saved_textures.size() / max_saved_textures_1d) * saved_texture_dim;

        //glBindTexture(GL_TEXTURE_2D, 0);

        GL_State->bind(atlas_fbo);
        //glViewport(0,0,atlas_texture.width, atlas_tetxure.height);

        saved_textures.push_back(saved_texture_t{filepath});

        ASSERT(!CheckGLError(), "GL Error in texture_bank_t::add_texture() for \'%s\'", filepath.c_str());
    }
}
}
}<commit_msg>more WIP texture bank stuff attempting to render an added texture onto the atlas using a framebuffer object<commit_after>#include "stdafx.h"
#include "texture_bank.h"

#include <glm/gtc/matrix_transform.hpp>

#include "asdf_multiplat/data/gl_resources.h"
#include "asdf_multiplat/utilities/utilities.h"
#include "asdf_multiplat/utilities/cjson_utils.hpp"

using namespace std;

namespace asdf
{
    using namespace util;

namespace hexmap {
namespace data
{

    texture_bank_t::texture_bank_t()
    : atlas_texture("hex texture atlas", nullptr, hex_atlas_dim, hex_atlas_dim)
    {
        ASSERT(!CheckGLError(), "GL Error Before Initializing texture_bank_t");

        {
            GL_State->bind(atlas_fbo);
            glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, atlas_texture.texture_id, 0);

            GLenum draw_buffers = GL_COLOR_ATTACHMENT1;
            glDrawBuffers(1, &draw_buffers);
            ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "GL Error creating texture bank framebuffer");

            glViewport(0,0,atlas_texture.width, atlas_texture.height);

            glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            GL_State->unbind_fbo();
        }

        auto dir = find_folder("data");
        ASSERT(dir.length() > 0, "Could not find data folder");

        auto imported_textures_json_filepath = dir + "/" + string(imported_textures_json_filename);

        std::string json_str = read_text_file(imported_textures_json_filepath);
        cJSON* root = cJSON_Parse(json_str.c_str());
        ASSERT(root, "Error loading imported textures json file");

        vector<char*> textures;
        CJSON_GET_STR_VECTOR(textures);

        for(auto const& filepath : textures)
        {
            if(is_file(filepath))
            {
                add_texture(filepath);
            }
            else
            {
                LOG("Texture not found at %s", filepath);
            }
        }

        cJSON_Delete(root);

        ASSERT(!CheckGLError(), "GL Error Initializing texture_bank_t");
    }

    void texture_bank_t::add_texture(std::string const& filepath)
    {
        auto prev_fbo = GL_State->current_framebuffer;

        ASSERT(is_file(filepath), "File not found %s", filepath.c_str());
        texture_t new_texture(filepath, SOIL_LOAD_RGBA); //force RGBA, since that's what the atlas uses. Might not be neccesary now that I'm rendering to a framebuffer

        //ASSERT(new_texture.format == atlas_texture.format, "Color format of texture must match the atlas (GL_RGBA)   %s", filepath.c_str());
        //ASSERT(new_texture.types[0] == atlas_texture.types[0], "");

        int dest_loc_x = (saved_textures.size() % max_saved_textures_1d) * saved_texture_dim;
        int dest_loc_y = (saved_textures.size() / max_saved_textures_1d) * saved_texture_dim;

        GL_State->bind(atlas_fbo);
        glViewport(0,0,atlas_texture.width, atlas_texture.height);

        ASSERT(!CheckGLError(), "");
        auto& screen_shader = app.renderer->screen_shader;
        GL_State->bind(screen_shader);

        screen_shader->world_matrix[3][0] = dest_loc_x;
        screen_shader->world_matrix[3][1] = dest_loc_y;
        screen_shader->world_matrix = glm::scale(screen_shader->world_matrix, glm::vec3(1000.0f, 1000.0f, 1.0f));
        screen_shader->projection_matrix = glm::ortho<float>(0, atlas_texture.width, 0, atlas_texture.height/*, -1.0f, 1.0f*/);
        screen_shader->update_wvp_uniform();

        glUniform4f(screen_shader->uniform("Color"), 1.5f, 1.0f, 1.0f, 1.0f);
        glBindTexture(GL_TEXTURE_2D, new_texture.texture_id);

        app.renderer->quad.render();

        //re-bind prev fbo
        glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo);
        GL_State->current_framebuffer = prev_fbo;

        saved_textures.push_back(saved_texture_t{filepath});

        ASSERT(!CheckGLError(), "GL Error in texture_bank_t::add_texture() for \'%s\'", filepath.c_str());
    }
}
}
}<|endoftext|>


<commit_before>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Lease.hxx"
#include "fb_pool.hxx"
#include "net/SocketProtocolError.hxx"

FilteredSocketLease::FilteredSocketLease(FilteredSocket &_socket, Lease &lease,
                                         const struct timeval *read_timeout,
                                         const struct timeval *write_timeout,
                                         BufferedSocketHandler &_handler) noexcept
    :socket(&_socket), handler(_handler)
{
    socket->Reinit(read_timeout, write_timeout, *this);
    lease_ref.Set(lease);
}

FilteredSocketLease::~FilteredSocketLease() noexcept
{
    assert(IsReleased());

    for (auto &i : input)
        i.FreeIfDefined(fb_pool_get());
}

void
FilteredSocketLease::Release(bool reuse) noexcept
{
    // TODO: move buffers instead of copying the data
    size_t i = 0;
    while (true) {
        auto r = WritableBuffer<uint8_t>::FromVoid(socket->ReadBuffer());
        if (r.empty())
            break;

        auto &dest = input[i];
        if (!dest.IsDefined())
            dest.Allocate(fb_pool_get());
        else if (dest.IsFull()) {
            ++i;
            assert(i < input.size());
            continue;
        }

        auto w = dest.Write();
        size_t n = std::min(r.size, w.size);
        assert(n > 0);
        std::move(r.data, r.data + n, w.data);
        socket->Consumed(n);
        dest.Append(n);
    }

    lease_ref.Release(reuse);
    socket = nullptr;
}

bool
FilteredSocketLease::IsEmpty() const noexcept
{
    if (IsReleased())
        return input.front().IsEmpty();
    else
        return socket->IsEmpty();
}

size_t
FilteredSocketLease::GetAvailable() const noexcept
{
    if (IsReleased()) {
        size_t result = 0;
        for (const auto &i : input)
            result += i.GetAvailable();
        return result;
    } else
        return socket->GetAvailable();
}

WritableBuffer<void>
FilteredSocketLease::ReadBuffer() const noexcept
{
    return IsReleased()
        ? input.front().Read().ToVoid()
        : socket->ReadBuffer();
}

void
FilteredSocketLease::Consumed(size_t nbytes) noexcept
{
    if (IsReleased()) {
        input.front().Consume(nbytes);
        MoveInput();
    } else
        socket->Consumed(nbytes);
}

bool
FilteredSocketLease::Read(bool expect_more) noexcept
{
    if (IsReleased()) {
        while (true) {
            auto r = input.front().Read();
            if (r.empty())
                return true;

            switch (handler.OnBufferedData()) {
            case BufferedResult::OK:
                if (IsEmpty() && !handler.OnBufferedEnd())
                    return false;
                break;

            case BufferedResult::BLOCKING:
                assert(!input.front().IsEmpty());
                return true;

            case BufferedResult::MORE:
            case BufferedResult::AGAIN_OPTIONAL:
            case BufferedResult::AGAIN_EXPECT:
                break;

            case BufferedResult::CLOSED:
                return false;
            }
        }
    } else
        return socket->Read(expect_more);
}

void
FilteredSocketLease::MoveInput() noexcept
{
    auto &dest = input.front();
    for (size_t i = 1; !dest.IsFull() && i < input.size(); ++i) {
        auto &src = input[i];
        dest.MoveFromAllowBothNull(src);
        src.FreeIfEmpty(fb_pool_get());
    }
}

BufferedResult
FilteredSocketLease::OnBufferedData()
{
    while (true) {
        const auto result = handler.OnBufferedData();
        if (result == BufferedResult::CLOSED)
            break;

        if (!IsReleased())
            return result;

        /* since the BufferedSocket is gone already, we must handle
           the AGAIN result codes here */

        if (result == BufferedResult::AGAIN_OPTIONAL && !IsEmpty())
            continue;
        else if (result == BufferedResult::AGAIN_EXPECT) {
            if (IsEmpty()) {
                handler.OnBufferedError(std::make_exception_ptr(SocketClosedPrematurelyError()));
                break;
            }

            continue;
        } else
            break;
    }

    /* if the socket has been released, we must always report CLOSED
       to the released BufferedSocket instance, even if our handler
       still wants to consume the remaining buffer */
    return BufferedResult::CLOSED;
}

DirectResult
FilteredSocketLease::OnBufferedDirect(SocketDescriptor fd, FdType fd_type)
{
    return handler.OnBufferedDirect(fd, fd_type);
}

bool
FilteredSocketLease::OnBufferedClosed() noexcept
{
    auto result = handler.OnBufferedClosed();
    if (result && IsReleased()) {
        result = false;

        if (handler.OnBufferedRemaining(GetAvailable()) &&
            IsEmpty())
            handler.OnBufferedEnd();
    }

    return result;
}

bool
FilteredSocketLease::OnBufferedRemaining(size_t remaining) noexcept
{
    auto result = handler.OnBufferedRemaining(remaining);
    if (result && IsReleased())
        result = false;
    return result;
}

bool
FilteredSocketLease::OnBufferedEnd() noexcept
{
    return handler.OnBufferedEnd();
}

bool
FilteredSocketLease::OnBufferedWrite()
{
    return handler.OnBufferedWrite();
}

bool
FilteredSocketLease::OnBufferedDrained() noexcept
{
    return handler.OnBufferedDrained();
}

bool
FilteredSocketLease::OnBufferedTimeout() noexcept
{
    return handler.OnBufferedTimeout();
}

enum write_result
FilteredSocketLease::OnBufferedBroken() noexcept
{
    return handler.OnBufferedBroken();
}

void
FilteredSocketLease::OnBufferedError(std::exception_ptr e) noexcept
{
    return handler.OnBufferedError(e);
}
<commit_msg>fs/Lease: add assertions<commit_after>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Lease.hxx"
#include "fb_pool.hxx"
#include "net/SocketProtocolError.hxx"

FilteredSocketLease::FilteredSocketLease(FilteredSocket &_socket, Lease &lease,
                                         const struct timeval *read_timeout,
                                         const struct timeval *write_timeout,
                                         BufferedSocketHandler &_handler) noexcept
    :socket(&_socket), handler(_handler)
{
    socket->Reinit(read_timeout, write_timeout, *this);
    lease_ref.Set(lease);
}

FilteredSocketLease::~FilteredSocketLease() noexcept
{
    assert(IsReleased());

    for (auto &i : input)
        i.FreeIfDefined(fb_pool_get());
}

void
FilteredSocketLease::Release(bool reuse) noexcept
{
    assert(!IsReleased());
    assert(!lease_ref.released);

    // TODO: move buffers instead of copying the data
    size_t i = 0;
    while (true) {
        auto r = WritableBuffer<uint8_t>::FromVoid(socket->ReadBuffer());
        if (r.empty())
            break;

        auto &dest = input[i];
        if (!dest.IsDefined())
            dest.Allocate(fb_pool_get());
        else if (dest.IsFull()) {
            ++i;
            assert(i < input.size());
            continue;
        }

        auto w = dest.Write();
        size_t n = std::min(r.size, w.size);
        assert(n > 0);
        std::move(r.data, r.data + n, w.data);
        socket->Consumed(n);
        dest.Append(n);
    }

    lease_ref.Release(reuse);
    socket = nullptr;
}

bool
FilteredSocketLease::IsEmpty() const noexcept
{
    if (IsReleased())
        return input.front().IsEmpty();
    else
        return socket->IsEmpty();
}

size_t
FilteredSocketLease::GetAvailable() const noexcept
{
    if (IsReleased()) {
        size_t result = 0;
        for (const auto &i : input)
            result += i.GetAvailable();
        return result;
    } else
        return socket->GetAvailable();
}

WritableBuffer<void>
FilteredSocketLease::ReadBuffer() const noexcept
{
    return IsReleased()
        ? input.front().Read().ToVoid()
        : socket->ReadBuffer();
}

void
FilteredSocketLease::Consumed(size_t nbytes) noexcept
{
    if (IsReleased()) {
        input.front().Consume(nbytes);
        MoveInput();
    } else
        socket->Consumed(nbytes);
}

bool
FilteredSocketLease::Read(bool expect_more) noexcept
{
    if (IsReleased()) {
        while (true) {
            auto r = input.front().Read();
            if (r.empty())
                return true;

            switch (handler.OnBufferedData()) {
            case BufferedResult::OK:
                if (IsEmpty() && !handler.OnBufferedEnd())
                    return false;
                break;

            case BufferedResult::BLOCKING:
                assert(!input.front().IsEmpty());
                return true;

            case BufferedResult::MORE:
            case BufferedResult::AGAIN_OPTIONAL:
            case BufferedResult::AGAIN_EXPECT:
                break;

            case BufferedResult::CLOSED:
                return false;
            }
        }
    } else
        return socket->Read(expect_more);
}

void
FilteredSocketLease::MoveInput() noexcept
{
    auto &dest = input.front();
    for (size_t i = 1; !dest.IsFull() && i < input.size(); ++i) {
        auto &src = input[i];
        dest.MoveFromAllowBothNull(src);
        src.FreeIfEmpty(fb_pool_get());
    }
}

BufferedResult
FilteredSocketLease::OnBufferedData()
{
    while (true) {
        const auto result = handler.OnBufferedData();
        if (result == BufferedResult::CLOSED)
            break;

        if (!IsReleased())
            return result;

        /* since the BufferedSocket is gone already, we must handle
           the AGAIN result codes here */

        if (result == BufferedResult::AGAIN_OPTIONAL && !IsEmpty())
            continue;
        else if (result == BufferedResult::AGAIN_EXPECT) {
            if (IsEmpty()) {
                handler.OnBufferedError(std::make_exception_ptr(SocketClosedPrematurelyError()));
                break;
            }

            continue;
        } else
            break;
    }

    /* if the socket has been released, we must always report CLOSED
       to the released BufferedSocket instance, even if our handler
       still wants to consume the remaining buffer */
    return BufferedResult::CLOSED;
}

DirectResult
FilteredSocketLease::OnBufferedDirect(SocketDescriptor fd, FdType fd_type)
{
    return handler.OnBufferedDirect(fd, fd_type);
}

bool
FilteredSocketLease::OnBufferedClosed() noexcept
{
    auto result = handler.OnBufferedClosed();
    if (result && IsReleased()) {
        result = false;

        if (handler.OnBufferedRemaining(GetAvailable()) &&
            IsEmpty())
            handler.OnBufferedEnd();
    }

    return result;
}

bool
FilteredSocketLease::OnBufferedRemaining(size_t remaining) noexcept
{
    auto result = handler.OnBufferedRemaining(remaining);
    if (result && IsReleased())
        result = false;
    return result;
}

bool
FilteredSocketLease::OnBufferedEnd() noexcept
{
    return handler.OnBufferedEnd();
}

bool
FilteredSocketLease::OnBufferedWrite()
{
    return handler.OnBufferedWrite();
}

bool
FilteredSocketLease::OnBufferedDrained() noexcept
{
    return handler.OnBufferedDrained();
}

bool
FilteredSocketLease::OnBufferedTimeout() noexcept
{
    return handler.OnBufferedTimeout();
}

enum write_result
FilteredSocketLease::OnBufferedBroken() noexcept
{
    return handler.OnBufferedBroken();
}

void
FilteredSocketLease::OnBufferedError(std::exception_ptr e) noexcept
{
    return handler.OnBufferedError(e);
}
<|endoftext|>


<commit_before>#include "board.hpp"
#include "config.hpp"

namespace roadagain
{

Config::Config() : use_color_(true), automatic_(false), player_(BLACK)
{
}

Config::Config(const Config& config)
{
}

Config& Config::instance()
{
    return (Config::instance_);
}

Config& Config::operator=(const Config& config)
{
}

}

#endif
<commit_msg>Kicked out needless endif<commit_after>#include "board.hpp"
#include "config.hpp"

namespace roadagain
{

Config::Config() : use_color_(true), automatic_(false), player_(BLACK)
{
}

Config::Config(const Config& config)
{
}

Config& Config::instance()
{
    return (Config::instance_);
}

Config& Config::operator=(const Config& config)
{
}

}
<|endoftext|>


<commit_before>#ifndef CONFIG_HPP
#define CONFIG_HPP

const int SCREEN_WIDTH = 256;
const int SCREEN_HEIGHT = 144;
const int INITIAL_WINDOW_WIDTH = SCREEN_WIDTH;
const int INITIAL_WINDOW_HEIGHT = SCREEN_HEIGHT;

#endif<commit_msg>changed resolution (hopefully for last time)<commit_after>#ifndef CONFIG_HPP
#define CONFIG_HPP

const int SCREEN_WIDTH = 320;
const int SCREEN_HEIGHT = 180;
const int INITIAL_WINDOW_WIDTH = SCREEN_WIDTH;
const int INITIAL_WINDOW_HEIGHT = SCREEN_HEIGHT;

#endif<|endoftext|>