<commit_before>#include "program_renderer.hpp"
#include "mmd-physics/motion.hpp"

using namespace glm;
using namespace std;
using namespace mmd;

using mmd::pmx::Vertex;
using mmd::physics::Motion;

proto(Character, Shader::character);

protoBuffer = {
    { 0, NULL },
    { 0, NULL },
    { 0, NULL },
};

protoAttrib = {
    { "position"  , Offset(Vertex, position[0])   , 3, sizeof(Vertex) },
    { "normal"    , Offset(Vertex, normal[0])     , 3, sizeof(Vertex) },
    { "uv"        , Offset(Vertex, uv[0])         , 2, sizeof(Vertex) },
    { "boneIndex" , Offset(Vertex, BDEF.bone[0])  , 4, sizeof(Vertex), true, GL_INT },
    { "boneWeight", Offset(Vertex, BDEF.weight[0]), 4, sizeof(Vertex) }
};

protoUnifom = {
    "mMat", "vMat", "pMat",
    "lightPosition", "lightColor", "ambient", "lightMaterial",
    "diffuse", "specular", "texture0", "side",
    "morphData", "morphCount", "morphs"
};

class Character : public ProgramRenderer<Proto> {
    static const int uboBinding = 1;

    Motion *motion;
    Model *model;
    vmd::Motion *vMotion;

    vector<mat4> bones;
    vector<float> morphs;
public:
    Character(Scene *scene, Model *model, mmd::vmd::Motion *motion)
        : ProgramRenderer(scene), motion(Motion::create()),
          model(model), vMotion(motion) {}

    ~Character() {}

    void setupBuffers() {
        int v = model->mesh.vertex.size();
        int s = model->mesh.surface.size();

        glGenBuffers(BufferSize, buffer);
        LOG << "generate " << BufferSize << " buffers";

        glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
        glBufferData(GL_ARRAY_BUFFER, v * sizeof(Vertex),
            &model->mesh.vertex[0], GL_STATIC_DRAW);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[1]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, s * sizeof(mmd::pmx::Surface),
            &model->mesh.surface[0], GL_STATIC_DRAW);

        glBindBuffer(GL_UNIFORM_BUFFER, buffer[2]);
        glBufferData(GL_UNIFORM_BUFFER, bones.size() * sizeof(mat4),
                     NULL, GL_DYNAMIC_DRAW);
        glBindBufferBase(GL_UNIFORM_BUFFER, uboBinding, buffer[2]);
    }

    void setup() {
        motion->loadModel(model);
        motion->loadMotion(vMotion);
        bones.resize(model->bones.size());
        morphs.resize(model->morphs.size());

        ProgramRenderer::setup();

        bindBuffer(buffer[0]);

        GLuint uboIndex = glGetUniformBlockIndex(program, "Bones");
        glUniformBlockBinding(program, uboIndex, uboBinding);

        glUniform1i(uniform[9], 0);
        glUniform1i(uniform[11], 1);
        glUniform1i(uniform[12], morphs.size());

        model->loadTextures();
        model->loadMorphTexture();
    }

    void render() {
        bindProgram();

        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);

        mat4 mMat(1.0f);
        swap(mMat[1], mMat[2]);
        mMat = scale(vec3(0.1f, 0.1f, 0.1f)) * mMat;
        mMat = translate(vec3(0.0f, 4.0f, 10.0f)) * mMat;

        glUniformMatrix4fv(uniform[0], 1, GL_FALSE, &mMat[0][0]);
        glUniformMatrix4fv(uniform[1], 1, GL_FALSE, &scene->vMat()[0][0]);
        glUniformMatrix4fv(uniform[2], 1, GL_FALSE, &scene->pMat()[0][0]);

        Light light = scene->light();

        glUniform4fv(uniform[3], 1, &light.position[0]);
        glUniform3fv(uniform[4], 1, &light.color[0]);
        glUniform4fv(uniform[6], 1, &light.material[0]);
        glUniform1fv(uniform[13], morphs.size(), &morphs[0]);

        glBindBuffer(GL_UNIFORM_BUFFER, buffer[2]);
        glBufferSubData(GL_UNIFORM_BUFFER, 0, bones.size() * sizeof(mat4),
                        &bones[0][0][0]);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_BUFFER, model->morphTexture());

        glActiveTexture(GL_TEXTURE0);

        int sum = 0;

        for (int i = 0; i < model->materials.size(); ++i) {
            const auto &material = model->materials[i];

            glUniform3fv(uniform[5], 1, &material.ambient[0]);
            glUniform4fv(uniform[7], 1, &material.diffuse[0]);
            glUniform4fv(uniform[8], 1, &material.specular[0]);

            glBindTexture(GL_TEXTURE_2D, model->texture(material.texture));

            glUniform1f(uniform[10], 1.0f);
            glCullFace(GL_FRONT);
            glDrawElements(GL_TRIANGLES, material.count,
                GL_UNSIGNED_INT, (void *)(sum * sizeof(GLuint)));

            if (material.flag & mmd::pmx::Material::DoubleSided) {
                glUniform1f(uniform[10], -1.0f);
                glCullFace(GL_BACK);
                glDrawElements(GL_TRIANGLES, material.count,
                    GL_UNSIGNED_INT, (void *)(sum * sizeof(GLuint)));
            }

            sum += material.count;
        }

        glDisable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);
    }

    void update() {
        static int frame = 0;
        motion->updateKey(frame);
        ++frame;

        for (int i = 0; i < bones.size(); ++i) {
            bones[i] = motion->skin(i);
        }
        for (int i = 0; i < morphs.size(); ++i) {
            morphs[i] = motion->face(i);
        }
    }

    void reset() {
        ProgramRenderer::reset();

        motion->reset();
    }
};

Renderer *ObjectBox::character(Scene *scene, Model *model, vmd::Motion *motion) {
    return create<Character>(scene, model, motion);
}
<commit_msg>add physics motion<commit_after>#include "program_renderer.hpp"
#include "mmd-physics/motion.hpp"

using namespace glm;
using namespace std;
using namespace mmd;

using mmd::pmx::Vertex;
using mmd::physics::Motion;

proto(Character, Shader::character);

protoBuffer = {
    { 0, NULL },
    { 0, NULL },
    { 0, NULL },
};

protoAttrib = {
    { "position"  , Offset(Vertex, position[0])   , 3, sizeof(Vertex) },
    { "normal"    , Offset(Vertex, normal[0])     , 3, sizeof(Vertex) },
    { "uv"        , Offset(Vertex, uv[0])         , 2, sizeof(Vertex) },
    { "boneIndex" , Offset(Vertex, BDEF.bone[0])  , 4, sizeof(Vertex), true, GL_INT },
    { "boneWeight", Offset(Vertex, BDEF.weight[0]), 4, sizeof(Vertex) }
};

protoUnifom = {
    "mMat", "vMat", "pMat",
    "lightPosition", "lightColor", "ambient", "lightMaterial",
    "diffuse", "specular", "texture0", "side",
    "morphData", "morphCount", "morphs"
};

class Character : public ProgramRenderer<Proto> {
    static const int uboBinding = 1;

    Motion *motion;
    Model *model;
    vmd::Motion *vMotion;

    vector<mat4> bones;
    vector<float> morphs;
public:
    Character(Scene *scene, Model *model, mmd::vmd::Motion *motion)
        : ProgramRenderer(scene), motion(Motion::create()),
          model(model), vMotion(motion) {}

    ~Character() {}

    void setupBuffers() {
        int v = model->mesh.vertex.size();
        int s = model->mesh.surface.size();

        glGenBuffers(BufferSize, buffer);
        LOG << "generate " << BufferSize << " buffers";

        glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
        glBufferData(GL_ARRAY_BUFFER, v * sizeof(Vertex),
            &model->mesh.vertex[0], GL_STATIC_DRAW);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[1]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, s * sizeof(mmd::pmx::Surface),
            &model->mesh.surface[0], GL_STATIC_DRAW);

        glBindBuffer(GL_UNIFORM_BUFFER, buffer[2]);
        glBufferData(GL_UNIFORM_BUFFER, bones.size() * sizeof(mat4),
                     NULL, GL_DYNAMIC_DRAW);
        glBindBufferBase(GL_UNIFORM_BUFFER, uboBinding, buffer[2]);
    }

    void setup() {
        motion->loadModel(model);
        motion->loadMotion(vMotion);
        bones.resize(model->bones.size());
        morphs.resize(model->morphs.size());

        ProgramRenderer::setup();

        bindBuffer(buffer[0]);

        GLuint uboIndex = glGetUniformBlockIndex(program, "Bones");
        glUniformBlockBinding(program, uboIndex, uboBinding);

        glUniform1i(uniform[9], 0);
        glUniform1i(uniform[11], 1);
        glUniform1i(uniform[12], morphs.size());

        model->loadTextures();
        model->loadMorphTexture();
    }

    void render() {
        bindProgram();

        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);

        mat4 mMat(1.0f);
        swap(mMat[1], mMat[2]);
        mMat = scale(vec3(0.1f, 0.1f, 0.1f)) * mMat;
        mMat = translate(vec3(0.0f, 4.0f, 10.0f)) * mMat;

        glUniformMatrix4fv(uniform[0], 1, GL_FALSE, &mMat[0][0]);
        glUniformMatrix4fv(uniform[1], 1, GL_FALSE, &scene->vMat()[0][0]);
        glUniformMatrix4fv(uniform[2], 1, GL_FALSE, &scene->pMat()[0][0]);

        Light light = scene->light();

        glUniform4fv(uniform[3], 1, &light.position[0]);
        glUniform3fv(uniform[4], 1, &light.color[0]);
        glUniform4fv(uniform[6], 1, &light.material[0]);
        glUniform1fv(uniform[13], morphs.size(), &morphs[0]);

        glBindBuffer(GL_UNIFORM_BUFFER, buffer[2]);
        glBufferSubData(GL_UNIFORM_BUFFER, 0, bones.size() * sizeof(mat4),
                        &bones[0][0][0]);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_BUFFER, model->morphTexture());

        glActiveTexture(GL_TEXTURE0);

        int sum = 0;

        for (int i = 0; i < model->materials.size(); ++i) {
            const auto &material = model->materials[i];

            glUniform3fv(uniform[5], 1, &material.ambient[0]);
            glUniform4fv(uniform[7], 1, &material.diffuse[0]);
            glUniform4fv(uniform[8], 1, &material.specular[0]);

            glBindTexture(GL_TEXTURE_2D, model->texture(material.texture));

            glUniform1f(uniform[10], 1.0f);
            glCullFace(GL_FRONT);
            glDrawElements(GL_TRIANGLES, material.count,
                GL_UNSIGNED_INT, (void *)(sum * sizeof(GLuint)));

            if (material.flag & mmd::pmx::Material::DoubleSided) {
                glUniform1f(uniform[10], -1.0f);
                glCullFace(GL_BACK);
                glDrawElements(GL_TRIANGLES, material.count,
                    GL_UNSIGNED_INT, (void *)(sum * sizeof(GLuint)));
            }

            sum += material.count;
        }

        glDisable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);
    }

    void update() {
        static int frame = 0;
        motion->updateKey(frame);
        motion->updatePhysics(Application::elapse);
        ++frame;

        for (int i = 0; i < bones.size(); ++i) {
            bones[i] = motion->skin(i);
        }
        for (int i = 0; i < morphs.size(); ++i) {
            morphs[i] = motion->face(i);
        }
    }

    void reset() {
        ProgramRenderer::reset();

        motion->reset();
    }
};

Renderer *ObjectBox::character(Scene *scene, Model *model, vmd::Motion *motion) {
    return create<Character>(scene, model, motion);
}
<|endoftext|>


<commit_before>/************************************************************************/
/*                                                                      */
/*               Copyright 1998-2002 by Ullrich Koethe                  */
/*       Cognitive Systems Group, University of Hamburg, Germany        */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    You may use, modify, and distribute this software according       */
/*    to the terms stated in the LICENSE file included in               */
/*    the VIGRA distribution.                                           */
/*                                                                      */
/*    The VIGRA Website is                                              */
/*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
/*    Please direct questions, bug reports, and contributions to        */
/*        koethe@informatik.uni-hamburg.de                              */
/*                                                                      */
/*  THIS SOFTWARE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR          */
/*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
/*                                                                      */
/************************************************************************/

#include <iostream>
#include "vigra/stdimage.hxx"
#include "vigra/stdimagefunctions.hxx"
#include "vigra/localminmax.hxx"
#include "vigra/labelimage.hxx"
#include "vigra/seededregiongrowing.hxx"
#include "vigra/impex.hxx"

using namespace vigra; // MSVC doesn't support Koenig lookup

// define a functor that calsulates the squared magnitude of the gradient
// given the x- and y- components of the gradient
struct GradientSquaredMagnitudeFunctor
{
    float operator()(float const & g1, float const & g2) const
    {
        return g1 * g1 + g2 * g2;
    }

    float operator()(vigra::RGBValue<float> const & rg1, vigra::RGBValue<float> const & rg2) const
    {
        float g1 = rg1.squaredMagnitude();
        float g2 = rg2.squaredMagnitude();

        return g1 * g1 + g2 * g2;
    }
};

// generic implementation of the watershed algorithm
template <class InImage, class OutImage>
void watershedSegmentation(InImage & in, OutImage & out, double scale)
{
    typedef typename vigra::NumericTraits<typename InImage::value_type>::RealPromote
        TmpType;

    int w = in.width();
    int h = in.height();

    vigra::BasicImage<TmpType> gradientx(w, h);
    vigra::BasicImage<TmpType> gradienty(w, h);
    vigra::FImage gradientmag(w, h);

    // calculate the x- and y-components of the image gradient at given scale
    recursiveFirstDerivativeX(srcImageRange(in), destImage(gradientx), scale);
    recursiveSmoothY(srcImageRange(gradientx), destImage(gradientx), scale);

    recursiveFirstDerivativeY(srcImageRange(in), destImage(gradienty), scale);
    recursiveSmoothX(srcImageRange(gradienty), destImage(gradienty), scale);

    // transform components into gradient magnitude
    combineTwoImages(srcImageRange(gradientx), srcImage(gradienty),
                     destImage(gradientmag), GradientSquaredMagnitudeFunctor());

    vigra::IImage labels(w, h);
    labels = 0;

    // find the local minima of the gradient magnitude
    // (might be larger than one pixel)
    extendedLocalMinima(srcImageRange(gradientmag), destImage(labels), 1);

    // label the minima just found
    int max_region_label =
        labelImageWithBackground(srcImageRange(labels), destImage(labels),
                                 false, 0);

    // create a statistics functor for region growing
    vigra::ArrayOfRegionStatistics<vigra::SeedRgDirectValueFunctor<float> >
                                          gradstat(max_region_label);

    // perform region growing, starting from the minima of the gradient magnitude;
    // as the feature (first input) image contains the gradient magnitude,
    // this calculates the catchment basin of each minimum
    seededRegionGrowing(srcImageRange(gradientmag), srcImage(labels),
                        destImage(labels), gradstat);

    // initialize a functor to determin the average gray-value or color
    // for each region (catchment basin) just found
    vigra::ArrayOfRegionStatistics<vigra::FindAverage<TmpType> >
                                          averages(max_region_label);

    // calculate the averages
    inspectTwoImages(srcImageRange(in), srcImage(labels), averages);

    // write the averages into the destination image (the functor 'averages'
    // acts as a look-up table)
    transformImage(srcImageRange(labels), destImage(out), averages);

    // mark the watershaed (region boundaries) black
    regionImageToEdgeImage(srcImageRange(labels), destImage(out),
                           vigra::NumericTraits<typename OutImage::value_type>::zero());

}

int main(int argc, char ** argv)
{
    if(argc != 3)
    {
        std::cout << "Usage: " << argv[0] << " infile outfile" << std::endl;
        std::cout << "(supported formats: " << vigra::impexListFormats() << ")" << std::endl;

        return 1;
    }

    try
    {
        vigra::ImageImportInfo info(argv[1]);

        // input width of gradient filter
        double scale = 1.0;
        std::cout << "Scale for gradient calculation ? ";
        std::cin >> scale;

        if(info.isGrayscale())
        {
            int w = info.width();
            int h = info.height();

            vigra::BImage in(w, h);
            importImage(info, destImage(in));

            vigra::BImage out(w, h);

            // perform watershed segmentation on gray image
            // note that the watershed algorithm usually results in an
            // oversegmentation (i.e., to many regions), but its boundary
            // localization is quite good
            watershedSegmentation(in, out, scale);

            std::cout << "Writing " << argv[2] << std::endl;
            exportImage(srcImageRange(out), vigra::ImageExportInfo(argv[2]));

        }
        else
        {
            int w = info.width();
            int h = info.height();

            vigra::BRGBImage in(w, h);
            importImage(info, destImage(in));

            vigra::BRGBImage out(w, h);

            // perform watershed segmentation on color image
            // note that the watershed algorithm usually results in an
            // oversegmentation (i.e., to many regions), but its boundary
            // localization is quite good
            watershedSegmentation(in, out, scale);

            std::cout << "Writing " << argv[2] << std::endl;
            exportImage(srcImageRange(out), vigra::ImageExportInfo(argv[2]));

        }
    }
    catch (vigra::StdException & e)
    {
        std::cout << e.what() << std::endl;
        return 1;
    }

    return 0;
}
<commit_msg>some speling fixes plus this little one: @@ -44,7 +44,7 @@ struct GradientSquaredMagnitudeFunctor          float g1 = rg1.squaredMagnitude();          float g2 = rg2.squaredMagnitude();<commit_after>/************************************************************************/
/*                                                                      */
/*               Copyright 1998-2002 by Ullrich Koethe                  */
/*       Cognitive Systems Group, University of Hamburg, Germany        */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    You may use, modify, and distribute this software according       */
/*    to the terms stated in the LICENSE file included in               */
/*    the VIGRA distribution.                                           */
/*                                                                      */
/*    The VIGRA Website is                                              */
/*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
/*    Please direct questions, bug reports, and contributions to        */
/*        koethe@informatik.uni-hamburg.de                              */
/*                                                                      */
/*  THIS SOFTWARE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR          */
/*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
/*                                                                      */
/************************************************************************/

#include <iostream>
#include "vigra/stdimage.hxx"
#include "vigra/stdimagefunctions.hxx"
#include "vigra/localminmax.hxx"
#include "vigra/labelimage.hxx"
#include "vigra/seededregiongrowing.hxx"
#include "vigra/impex.hxx"

using namespace vigra; // MSVC doesn't support Koenig lookup

// define a functor that calsulates the squared magnitude of the gradient
// given the x- and y- components of the gradient
struct GradientSquaredMagnitudeFunctor
{
    float operator()(float const & g1, float const & g2) const
    {
        return g1 * g1 + g2 * g2;
    }

    float operator()(vigra::RGBValue<float> const & rg1, vigra::RGBValue<float> const & rg2) const
    {
        float g1 = rg1.squaredMagnitude();
        float g2 = rg2.squaredMagnitude();

        return g1 + g2;
    }
};

// generic implementation of the watershed algorithm
template <class InImage, class OutImage>
void watershedSegmentation(InImage & in, OutImage & out, double scale)
{
    typedef typename vigra::NumericTraits<typename InImage::value_type>::RealPromote
        TmpType;

    int w = in.width();
    int h = in.height();

    vigra::BasicImage<TmpType> gradientx(w, h);
    vigra::BasicImage<TmpType> gradienty(w, h);
    vigra::FImage gradientmag(w, h);

    // calculate the x- and y-components of the image gradient at given scale
    recursiveFirstDerivativeX(srcImageRange(in), destImage(gradientx), scale);
    recursiveSmoothY(srcImageRange(gradientx), destImage(gradientx), scale);

    recursiveFirstDerivativeY(srcImageRange(in), destImage(gradienty), scale);
    recursiveSmoothX(srcImageRange(gradienty), destImage(gradienty), scale);

    // transform components into gradient magnitude
    combineTwoImages(srcImageRange(gradientx), srcImage(gradienty),
                     destImage(gradientmag), GradientSquaredMagnitudeFunctor());

    vigra::IImage labels(w, h);
    labels = 0;

    // find the local minima of the gradient magnitude
    // (might be larger than one pixel)
    extendedLocalMinima(srcImageRange(gradientmag), destImage(labels), 1);

    // label the minima just found
    int max_region_label =
        labelImageWithBackground(srcImageRange(labels), destImage(labels),
                                 false, 0);

    // create a statistics functor for region growing
    vigra::ArrayOfRegionStatistics<vigra::SeedRgDirectValueFunctor<float> >
                                          gradstat(max_region_label);

    // perform region growing, starting from the minima of the gradient magnitude;
    // as the feature (first input) image contains the gradient magnitude,
    // this calculates the catchment basin of each minimum
    seededRegionGrowing(srcImageRange(gradientmag), srcImage(labels),
                        destImage(labels), gradstat);

    // initialize a functor to determine the average gray-value or color
    // for each region (catchment basin) just found
    vigra::ArrayOfRegionStatistics<vigra::FindAverage<TmpType> >
                                          averages(max_region_label);

    // calculate the averages
    inspectTwoImages(srcImageRange(in), srcImage(labels), averages);

    // write the averages into the destination image (the functor 'averages'
    // acts as a look-up table)
    transformImage(srcImageRange(labels), destImage(out), averages);

    // mark the watersheds (region boundaries) black
    regionImageToEdgeImage(srcImageRange(labels), destImage(out),
                           vigra::NumericTraits<typename OutImage::value_type>::zero());
}

int main(int argc, char ** argv)
{
    if(argc != 3)
    {
        std::cout << "Usage: " << argv[0] << " infile outfile" << std::endl;
        std::cout << "(supported formats: " << vigra::impexListFormats() << ")" << std::endl;

        return 1;
    }

    try
    {
        vigra::ImageImportInfo info(argv[1]);

        // input width of gradient filter
        double scale = 1.0;
        std::cout << "Scale for gradient calculation ? ";
        std::cin >> scale;

        if(info.isGrayscale())
        {
            int w = info.width();
            int h = info.height();

            vigra::BImage in(w, h);
            importImage(info, destImage(in));

            vigra::BImage out(w, h);

            // perform watershed segmentation on gray image
            // note that the watershed algorithm usually results in an
            // oversegmentation (i.e., too many regions), but its boundary
            // localization is quite good
            watershedSegmentation(in, out, scale);

            std::cout << "Writing " << argv[2] << std::endl;
            exportImage(srcImageRange(out), vigra::ImageExportInfo(argv[2]));
        }
        else
        {
            int w = info.width();
            int h = info.height();

            vigra::BRGBImage in(w, h);
            importImage(info, destImage(in));

            vigra::BRGBImage out(w, h);

            // perform watershed segmentation on color image
            // note that the watershed algorithm usually results in an
            // oversegmentation (i.e., too many regions), but its boundary
            // localization is quite good
            watershedSegmentation(in, out, scale);

            std::cout << "Writing " << argv[2] << std::endl;
            exportImage(srcImageRange(out), vigra::ImageExportInfo(argv[2]));
        }
    }
    catch (vigra::StdException & e)
    {
        std::cout << e.what() << std::endl;
        return 1;
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <kernel/config.h>
#if HAVE_SYS_INOTIFY_H
# include <sys/inotify.h>
#endif

#include <libport/cassert>
#include <libport/compiler.hh>
#include <libport/dirent.h>
#include <libport/format.hh>
#include <libport/lockable.hh>
#include <libport/sys/types.h>
#include <libport/thread.hh>

#include <kernel/userver.hh>

#include <urbi/object/directory.hh>
#include <urbi/object/global.hh>
#include <urbi/object/path.hh>
#include <object/symbols.hh>

#include <urbi/runner/raise.hh>

using libport::BlockLock;

namespace urbi
{
  namespace object
  {
    /*--------------.
    | C++ methods.  |
    `--------------*/

    Directory::value_type
    Directory::value_get()
    {
      return path_;
    }

    /*---------------------.
    | urbiscript methods.  |
    `---------------------*/

#if HAVE_SYS_INOTIFY_H
    // Event polling thread
    typedef std::pair<rObject, rObject> _watch_map_elem_t;
    typedef boost::unordered_map<unsigned, _watch_map_elem_t> _watch_map_t;
    static _watch_map_t _watch_map;
    static libport::Lockable _watch_map_lock;
    static int _watch_fd;

    ATTRIBUTE_NORETURN
    static
    void poll()
    {
      while (true)
      {
        static const size_t name_size_max = 1024;
        static const size_t evt_size = sizeof(inotify_event);
        static const size_t buf_size = evt_size + name_size_max;

        char buffer[buf_size];
        const int len = read(_watch_fd, &buffer, buf_size);
        if (len < 0)
        {
          if (errno == EINTR)
            continue;
          else
            errnoabort("read failed");
        }
        int i = 0;
        while (i < len)
        {
          inotify_event& evt = reinterpret_cast<inotify_event&>(buffer[i]);
          i += evt_size + evt.len;

          rObject event;
          {
            BlockLock lock(_watch_map_lock);
            aver(libport::mhas(_watch_map, evt.wd));
            if (evt.mask & IN_CREATE)
              event = _watch_map[evt.wd].first;
            else if (evt.mask & IN_DELETE)
              event = _watch_map[evt.wd].second;
            else
              pabort("unrecognized inotify event");
          }

          {
            // FIXME: objects are refcounted and urbiserver->schedule is not
            // thread safe.
            object::objects_type args;
            args << new object::String(evt.name);
            ::kernel::urbiserver->schedule(event, SYMBOL(emit), args);
          }
        }
      }
    }
#endif

    // Construction
    Directory::Directory()
      : path_(new Path("/"))
    {
      proto_add(proto);
    }

    Directory::Directory(rDirectory model)
      : path_(model.get()->path_)
    {
      proto_add(model);
      create_events();
    }

    Directory::Directory(const std::string& value)
      : path_(new Path(value))
    {
      proto_add(proto ? rObject(proto) : Object::proto);
    }

    void
    Directory::create_events()
    {
#if HAVE_SYS_INOTIFY_H
      CAPTURE_GLOBAL(Event);
      on_file_created_ = Event->call("new");
      slot_set(SYMBOL(fileCreated), on_file_created_);
      on_file_deleted_ = Event->call("new");
      slot_set(SYMBOL(fileDeleted), on_file_deleted_);
#endif
    }

    void Directory::init(rPath path)
    {
      if (!path->exists())
        FRAISE("does not exist: %s", path->as_string());
      if (!path->is_dir())
        FRAISE("not a directory: %s", path->as_string());
      path_ = path;

#if HAVE_SYS_INOTIFY_H
      static bool started = false;
      if (!started)
      {
        _watch_fd = inotify_init();
        if (_watch_fd == -1)
          FRAISE("unable to start inotify: %s", libport::strerror(errno));
        libport::startThread(boost::function0<void>(poll));
      }
      started = true;
      int watch = inotify_add_watch(_watch_fd, path->as_string().c_str(),
                                    IN_CREATE | IN_DELETE);
      if (watch == -1)
        FRAISE("unable to watch directory: %s", libport::strerror(errno));
      {
        _watch_map_elem_t events(on_file_created_, on_file_deleted_);
        libport::BlockLock lock(_watch_map_lock);
        std::pair<_watch_map_t::iterator, bool> res =
          _watch_map.insert(_watch_map_t::value_type(watch, events));

        // inotify return a uniq identifier per path.  If events are
        // registered we just re-use them instead.  This is fine as long as
        // Directory are not mutable.
        if (!res.second)
        {
          // Update the directory references.
          events = res.first->second;
          on_file_created_ = events.first;
          on_file_deleted_ = events.second;
          // update the slots to make the modification visible in Urbiscript.
          slot_update(SYMBOL(fileCreated), on_file_created_, false);
          slot_update(SYMBOL(fileDeleted), on_file_deleted_, false);
        }
      }
#endif
    }

    void Directory::init(const std::string& path)
    {
      init(new Path(path));
    }

    // Conversions

    std::string Directory::as_string() const
    {
      return path_->as_string();
    }

    std::string Directory::as_printable() const
    {
      return libport::format("Directory(\"%s\")", path_->as_string());
    }

    // Stat
    template <rObject (*F) (Directory& d, const std::string& entry)>
    rList Directory::list()
    {
      List::value_type res;
      DIR* dir = opendir(path_->value_get().to_string().c_str());

      // There is already an appropriate error handling done for Path.
      // We can use it if we need it.
      if (!dir)
        path_->handle_any_error();

      while (dirent* entry = readdir(dir))
      {
        if (!entry)
  	path_->handle_any_error();
        std::string name = entry->d_name;
        if (name == "." || name == "..")
          continue;
        res << F(*this, name);
      }

      closedir(dir);
      return new List(res);
    }

    /*----------.
    | Details.  |
    `----------*/

    namespace details
    {
      rObject mk_string(Directory&, const std::string&);
      rObject mk_path(Directory&, const std::string&);

      rObject
      mk_string(Directory&, const std::string& entry)
      {
        return new String(entry);
      }

      rObject
      mk_path(Directory& d, const std::string& entry)
      {
        return new Path(d.value_get()->value_get() / entry);
      }
    }

    OVERLOAD_TYPE(init_bouncer, 1, 1,
                  Path,
                  (void (Directory::*)(rPath)) &Directory::init,
                  String,
                  (void (Directory::*)(const std::string&)) &Directory::init);

    /*----------.
    | Binding.  |
    `----------*/

    void
    Directory::initialize(CxxObject::Binder<Directory>& bind)
    {
      bind(SYMBOL(asList), &Directory::list<&details::mk_path>);
      bind(SYMBOL(asPrintable), &Directory::as_printable);
      bind(SYMBOL(asString), &Directory::as_string);
      bind(SYMBOL(content), &Directory::list<&details::mk_string>);

      rPrimitive p = new Primitive(&init_bouncer);
      proto->slot_set(SYMBOL(init), p);
    }

    URBI_CXX_OBJECT_REGISTER(Directory)
      : path_(new Path())
    {}
  }
}
<commit_msg>directory: s/unable to/cannot/.<commit_after>/*
 * Copyright (C) 2008-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <kernel/config.h>
#if HAVE_SYS_INOTIFY_H
# include <sys/inotify.h>
#endif

#include <libport/cassert>
#include <libport/compiler.hh>
#include <libport/dirent.h>
#include <libport/format.hh>
#include <libport/lockable.hh>
#include <libport/sys/types.h>
#include <libport/thread.hh>

#include <kernel/userver.hh>

#include <urbi/object/directory.hh>
#include <urbi/object/global.hh>
#include <urbi/object/path.hh>
#include <object/symbols.hh>

#include <urbi/runner/raise.hh>

using libport::BlockLock;

namespace urbi
{
  namespace object
  {
    /*--------------.
    | C++ methods.  |
    `--------------*/

    Directory::value_type
    Directory::value_get()
    {
      return path_;
    }

    /*---------------------.
    | urbiscript methods.  |
    `---------------------*/

#if HAVE_SYS_INOTIFY_H
    // Event polling thread
    typedef std::pair<rObject, rObject> _watch_map_elem_t;
    typedef boost::unordered_map<unsigned, _watch_map_elem_t> _watch_map_t;
    static _watch_map_t _watch_map;
    static libport::Lockable _watch_map_lock;
    static int _watch_fd;

    ATTRIBUTE_NORETURN
    static
    void poll()
    {
      while (true)
      {
        static const size_t name_size_max = 1024;
        static const size_t evt_size = sizeof(inotify_event);
        static const size_t buf_size = evt_size + name_size_max;

        char buffer[buf_size];
        const int len = read(_watch_fd, &buffer, buf_size);
        if (len < 0)
        {
          if (errno == EINTR)
            continue;
          else
            errnoabort("read failed");
        }
        int i = 0;
        while (i < len)
        {
          inotify_event& evt = reinterpret_cast<inotify_event&>(buffer[i]);
          i += evt_size + evt.len;

          rObject event;
          {
            BlockLock lock(_watch_map_lock);
            aver(libport::mhas(_watch_map, evt.wd));
            if (evt.mask & IN_CREATE)
              event = _watch_map[evt.wd].first;
            else if (evt.mask & IN_DELETE)
              event = _watch_map[evt.wd].second;
            else
              pabort("unrecognized inotify event");
          }

          {
            // FIXME: objects are refcounted and urbiserver->schedule is not
            // thread safe.
            object::objects_type args;
            args << new object::String(evt.name);
            ::kernel::urbiserver->schedule(event, SYMBOL(emit), args);
          }
        }
      }
    }
#endif

    // Construction
    Directory::Directory()
      : path_(new Path("/"))
    {
      proto_add(proto);
    }

    Directory::Directory(rDirectory model)
      : path_(model.get()->path_)
    {
      proto_add(model);
      create_events();
    }

    Directory::Directory(const std::string& value)
      : path_(new Path(value))
    {
      proto_add(proto ? rObject(proto) : Object::proto);
    }

    void
    Directory::create_events()
    {
#if HAVE_SYS_INOTIFY_H
      CAPTURE_GLOBAL(Event);
      on_file_created_ = Event->call("new");
      slot_set(SYMBOL(fileCreated), on_file_created_);
      on_file_deleted_ = Event->call("new");
      slot_set(SYMBOL(fileDeleted), on_file_deleted_);
#endif
    }

    void Directory::init(rPath path)
    {
      if (!path->exists())
        FRAISE("does not exist: %s", path->as_string());
      if (!path->is_dir())
        FRAISE("not a directory: %s", path->as_string());
      path_ = path;

#if HAVE_SYS_INOTIFY_H
      static bool started = false;
      if (!started)
      {
        _watch_fd = inotify_init();
        if (_watch_fd == -1)
          FRAISE("cannot start inotify: %s", libport::strerror(errno));
        libport::startThread(boost::function0<void>(poll));
      }
      started = true;
      int watch = inotify_add_watch(_watch_fd, path->as_string().c_str(),
                                    IN_CREATE | IN_DELETE);
      if (watch == -1)
        FRAISE("cannot watch directory: %s", libport::strerror(errno));
      {
        _watch_map_elem_t events(on_file_created_, on_file_deleted_);
        libport::BlockLock lock(_watch_map_lock);
        std::pair<_watch_map_t::iterator, bool> res =
          _watch_map.insert(_watch_map_t::value_type(watch, events));

        // inotify return a uniq identifier per path.  If events are
        // registered we just re-use them instead.  This is fine as long as
        // Directory are not mutable.
        if (!res.second)
        {
          // Update the directory references.
          events = res.first->second;
          on_file_created_ = events.first;
          on_file_deleted_ = events.second;
          // update the slots to make the modification visible in Urbiscript.
          slot_update(SYMBOL(fileCreated), on_file_created_, false);
          slot_update(SYMBOL(fileDeleted), on_file_deleted_, false);
        }
      }
#endif
    }

    void Directory::init(const std::string& path)
    {
      init(new Path(path));
    }

    // Conversions

    std::string Directory::as_string() const
    {
      return path_->as_string();
    }

    std::string Directory::as_printable() const
    {
      return libport::format("Directory(\"%s\")", path_->as_string());
    }

    // Stat
    template <rObject (*F) (Directory& d, const std::string& entry)>
    rList Directory::list()
    {
      List::value_type res;
      DIR* dir = opendir(path_->value_get().to_string().c_str());

      // There is already an appropriate error handling done for Path.
      // We can use it if we need it.
      if (!dir)
        path_->handle_any_error();

      while (dirent* entry = readdir(dir))
      {
        if (!entry)
	path_->handle_any_error();
        std::string name = entry->d_name;
        if (name == "." || name == "..")
          continue;
        res << F(*this, name);
      }

      closedir(dir);
      return new List(res);
    }

    /*----------.
    | Details.  |
    `----------*/

    namespace details
    {
      rObject mk_string(Directory&, const std::string&);
      rObject mk_path(Directory&, const std::string&);

      rObject
      mk_string(Directory&, const std::string& entry)
      {
        return new String(entry);
      }

      rObject
      mk_path(Directory& d, const std::string& entry)
      {
        return new Path(d.value_get()->value_get() / entry);
      }
    }

    OVERLOAD_TYPE(init_bouncer, 1, 1,
                  Path,
                  (void (Directory::*)(rPath)) &Directory::init,
                  String,
                  (void (Directory::*)(const std::string&)) &Directory::init);

    /*----------.
    | Binding.  |
    `----------*/

    void
    Directory::initialize(CxxObject::Binder<Directory>& bind)
    {
      bind(SYMBOL(asList), &Directory::list<&details::mk_path>);
      bind(SYMBOL(asPrintable), &Directory::as_printable);
      bind(SYMBOL(asString), &Directory::as_string);
      bind(SYMBOL(content), &Directory::list<&details::mk_string>);

      rPrimitive p = new Primitive(&init_bouncer);
      proto->slot_set(SYMBOL(init), p);
    }

    URBI_CXX_OBJECT_REGISTER(Directory)
      : path_(new Path())
    {}
  }
}
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2010 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/SamsungV2Decompressor.h"
#include "common/Common.h"                // for uint32, ushort16, int32
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB32.h"              // for BitPumpMSB32
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for max
#include <cassert>                        // for assert
#include <type_traits>                    // for underlying_type, underlyin...

namespace rawspeed {

// Seriously Samsung just use lossless jpeg already, it compresses better too :)

// Thanks to Michael Reichmann (Luminous Landscape) for putting Pedro Côrte-Real
// in contact and Loring von Palleske (Samsung) for pointing to the open-source
// code of Samsung's DNG converter at http://opensource.samsung.com/

enum struct SamsungV2Decompressor::OptFlags : uint32 {
  NONE = 0U,       // no flags
  SKIP = 1U << 0U, // Skip checking if we need differences from previous line
  MV = 1U << 1U,   // Simplify motion vector definition
  QP = 1U << 2U,   // Don't scale the diff values

  // all possible flags
  ALL = SKIP | MV | QP,
};

constexpr SamsungV2Decompressor::OptFlags
operator|(SamsungV2Decompressor::OptFlags lhs,
          SamsungV2Decompressor::OptFlags rhs) {
  return static_cast<SamsungV2Decompressor::OptFlags>(
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          lhs) |
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          rhs));
}

constexpr bool operator&(SamsungV2Decompressor::OptFlags lhs,
                         SamsungV2Decompressor::OptFlags rhs) {
  return SamsungV2Decompressor::OptFlags::NONE !=
         static_cast<SamsungV2Decompressor::OptFlags>(
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 lhs) &
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 rhs));
}

SamsungV2Decompressor::SamsungV2Decompressor(const RawImage& image,
                                             const ByteStream& bs, int bit)
    : AbstractSamsungDecompressor(image), bits(bit) {
  BitPumpMSB32 startpump(bs);

  // Process the initial metadata bits, we only really use initVal, width and
  // height (the last two match the TIFF values anyway)
  startpump.getBits(16); // NLCVersion
  startpump.getBits(4);  // ImgFormat
  bitDepth = startpump.getBits(4) + 1;
  startpump.getBits(4); // NumBlkInRCUnit
  startpump.getBits(4); // CompressionRatio
  width = startpump.getBits(16);
  height = startpump.getBits(16);
  startpump.getBits(16); // TileWidth
  startpump.getBits(4);  // reserved

  // The format includes an optimization code that sets 3 flags to change the
  // decoding parameters
  const uint32 optflags = startpump.getBits(4);
  if (optflags > static_cast<uint32>(OptFlags::ALL))
    ThrowRDE("Invalid opt flags %x", optflags);
  _flags = static_cast<OptFlags>(optflags);

  startpump.getBits(8); // OverlapWidth
  startpump.getBits(8); // reserved
  startpump.getBits(8); // Inc
  startpump.getBits(2); // reserved
  initVal = startpump.getBits(14);

  if (width == 0 || height == 0 || width % 16 != 0 || width > 6496 ||
      height > 4336)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);

  if (width != static_cast<uint32>(mRaw->dim.x) ||
      height != static_cast<uint32>(mRaw->dim.y))
    ThrowRDE("EXIF image dimensions do not match dimensions from raw header");

  data = startpump.getStream(startpump.getRemainSize());
}

void SamsungV2Decompressor::decompress() {
  switch (_flags) {
  case OptFlags::NONE:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::NONE>(row);
    break;
  case OptFlags::ALL:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::ALL>(row);
    break;

  case OptFlags::SKIP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP>(row);
    break;
  case OptFlags::MV:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::MV>(row);
    break;
  case OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::QP>(row);
    break;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
  case OptFlags::SKIP | OptFlags::MV:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::MV>(row);
    break;
  case OptFlags::SKIP | OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::QP>(row);
    break;

  case OptFlags::MV | OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::MV | OptFlags::QP>(row);
    break;
#pragma GCC diagnostic pop

  default:
    __builtin_unreachable();
  }
}

template <SamsungV2Decompressor::OptFlags optflags>
void SamsungV2Decompressor::decompressRow(uint32 row) {
  // The format is relatively straightforward. Each line gets encoded as a set
  // of differences from pixels from another line. Pixels are grouped in blocks
  // of 16 (8 green, 8 red or blue). Each block is encoded in three sections.
  // First 1 or 4 bits to specify which reference pixels to use, then a section
  // that specifies for each pixel the number of bits in the difference, then
  // the actual difference bits

  // Align pump to 16byte boundary
  const auto line_offset = data.getPosition();
  if ((line_offset & 0xf) != 0)
    data.skipBytes(16 - (line_offset & 0xf));

  BitPumpMSB32 pump(data);

  auto* img = reinterpret_cast<ushort16*>(mRaw->getData(0, row));
  ushort16* img_up = reinterpret_cast<ushort16*>(
      mRaw->getData(0, std::max(0, static_cast<int>(row) - 1)));
  ushort16* img_up2 = reinterpret_cast<ushort16*>(
      mRaw->getData(0, std::max(0, static_cast<int>(row) - 2)));

  // Initialize the motion and diff modes at the start of the line
  uint32 motion = 7;
  // By default we are not scaling values at all
  int32 scale = 0;

  uint32 diffBitsMode[3][2] = {{0}};
  for (auto& i : diffBitsMode)
    i[0] = i[1] = (row == 0 || row == 1) ? 7 : 4;

  assert(width >= 16);
  assert(width % 16 == 0);
  for (uint32 col = 0; col < width; col += 16) {
    if (!(optflags & OptFlags::QP) && !(col & 63)) {
      static constexpr int32 scalevals[] = {0, -2, 2};
      uint32 i = pump.getBits(2);
      scale = i < 3 ? scale + scalevals[i] : pump.getBits(12);
    }

    // First we figure out which reference pixels mode we're in
    if (optflags & OptFlags::MV)
      motion = pump.getBits(1) ? 3 : 7;
    else if (!pump.getBits(1))
      motion = pump.getBits(3);

    if ((row == 0 || row == 1) && (motion != 7))
      ThrowRDE("At start of image and motion isn't 7. File corrupted?");

    if (motion == 7) {
      // The base case, just set all pixels to the previous ones on the same
      // line If we're at the left edge we just start at the initial value
      for (uint32 i = 0; i < 16; i++)
        img[i] = (col == 0) ? initVal : *(img + i - 2);
    } else {
      // The complex case, we now need to actually lookup one or two lines
      // above
      if (row < 2)
        ThrowRDE(
            "Got a previous line lookup on first two lines. File corrupted?");

      static constexpr int32 motionOffset[7] = {-4, -2, -2, 0, 0, 2, 4};
      static constexpr int32 motionDoAverage[7] = {0, 0, 1, 0, 1, 0, 0};

      int32 slideOffset = motionOffset[motion];
      int32 doAverage = motionDoAverage[motion];

      for (uint32 i = 0; i < 16; i++) {
        ushort16* line;
        ushort16* refpixel;

        if ((row + i) & 0x1) {
          // Red or blue pixels use same color two lines up
          line = img_up2;
          refpixel = line + i + slideOffset;
        } else {
          // Green pixel N uses Green pixel N from row above
          // (top left or top right)
          line = img_up;
          refpixel = line + i + slideOffset + (((i % 2) != 0) ? -1 : 1);
        }

        if (col == 0 && line > refpixel)
          ThrowRDE("Bad motion %u at the beginning of the row", motion);
        if (col + 16 == width && ((refpixel >= line + 16) ||
                                  (doAverage && (refpixel + 2 >= line + 16))))
          ThrowRDE("Bad motion %u at the end of the row", motion);

        // In some cases we use as reference interpolation of this pixel and
        // the next
        if (doAverage)
          img[i] = (*refpixel + *(refpixel + 2) + 1) >> 1;
        else
          img[i] = *refpixel;
      }
    }

    // Figure out how many difference bits we have to read for each pixel
    uint32 diffBits[4] = {0};
    if (optflags & OptFlags::SKIP || !pump.getBits(1)) {
      uint32 flags[4];
      for (unsigned int& flag : flags)
        flag = pump.getBits(2);

      for (uint32 i = 0; i < 4; i++) {
        // The color is 0-Green 1-Blue 2-Red
        uint32 colornum = (row % 2 != 0) ? i >> 1 : ((i >> 1) + 2) % 3;

        assert(flags[i] <= 3);
        switch (flags[i]) {
        case 0:
          diffBits[i] = diffBitsMode[colornum][0];
          break;
        case 1:
          diffBits[i] = diffBitsMode[colornum][0] + 1;
          break;
        case 2:
          diffBits[i] = diffBitsMode[colornum][0] - 1;
          break;
        case 3:
          diffBits[i] = pump.getBits(4);
          break;
        default:
          __builtin_unreachable();
        }

        diffBitsMode[colornum][0] = diffBitsMode[colornum][1];
        diffBitsMode[colornum][1] = diffBits[i];

        if (diffBits[i] > bitDepth + 1)
          ThrowRDE("Too many difference bits. File corrupted?");
      }
    }

    // Actually read the differences and write them to the pixels
    for (uint32 i = 0; i < 16; i++) {
      uint32 len = diffBits[i >> 2];
      int32 diff = pump.getBits(len);

      // If the first bit is 1 we need to turn this into a negative number
      if (len != 0 && diff >> (len - 1))
        diff -= (1 << len);

      ushort16* value = nullptr;
      // Apply the diff to pixels 0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
      if (row % 2)
        value = &img[((i & 0x7) << 1) + 1 - (i >> 3)];
      else
        value = &img[((i & 0x7) << 1) + (i >> 3)];

      diff = diff * (scale * 2 + 1) + scale;
      *value = clampBits(static_cast<int>(*value) + diff, bits);
    }

    img += 16;
    img_up += 16;
    img_up2 += 16;
  }

  data.skipBytes(pump.getBufferPosition());
}

} // namespace rawspeed
<commit_msg>SamsungV2Decompressor: sanitize image dimensions/bpp<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2010 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/SamsungV2Decompressor.h"
#include "common/Common.h"                // for uint32, ushort16, int32
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB32.h"              // for BitPumpMSB32
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for max
#include <cassert>                        // for assert
#include <type_traits>                    // for underlying_type, underlyin...

namespace rawspeed {

// Seriously Samsung just use lossless jpeg already, it compresses better too :)

// Thanks to Michael Reichmann (Luminous Landscape) for putting Pedro Côrte-Real
// in contact and Loring von Palleske (Samsung) for pointing to the open-source
// code of Samsung's DNG converter at http://opensource.samsung.com/

enum struct SamsungV2Decompressor::OptFlags : uint32 {
  NONE = 0U,       // no flags
  SKIP = 1U << 0U, // Skip checking if we need differences from previous line
  MV = 1U << 1U,   // Simplify motion vector definition
  QP = 1U << 2U,   // Don't scale the diff values

  // all possible flags
  ALL = SKIP | MV | QP,
};

constexpr SamsungV2Decompressor::OptFlags
operator|(SamsungV2Decompressor::OptFlags lhs,
          SamsungV2Decompressor::OptFlags rhs) {
  return static_cast<SamsungV2Decompressor::OptFlags>(
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          lhs) |
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          rhs));
}

constexpr bool operator&(SamsungV2Decompressor::OptFlags lhs,
                         SamsungV2Decompressor::OptFlags rhs) {
  return SamsungV2Decompressor::OptFlags::NONE !=
         static_cast<SamsungV2Decompressor::OptFlags>(
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 lhs) &
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 rhs));
}

SamsungV2Decompressor::SamsungV2Decompressor(const RawImage& image,
                                             const ByteStream& bs, int bit)
    : AbstractSamsungDecompressor(image), bits(bit) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  switch (bit) {
  case 12:
  case 14:
    break;
  default:
    ThrowRDE("Unexpected bit per pixel (%u)", bit);
  }

  BitPumpMSB32 startpump(bs);

  // Process the initial metadata bits, we only really use initVal, width and
  // height (the last two match the TIFF values anyway)
  startpump.getBits(16); // NLCVersion
  startpump.getBits(4);  // ImgFormat
  bitDepth = startpump.getBits(4) + 1;
  startpump.getBits(4); // NumBlkInRCUnit
  startpump.getBits(4); // CompressionRatio
  width = startpump.getBits(16);
  height = startpump.getBits(16);
  startpump.getBits(16); // TileWidth
  startpump.getBits(4);  // reserved

  // The format includes an optimization code that sets 3 flags to change the
  // decoding parameters
  const uint32 optflags = startpump.getBits(4);
  if (optflags > static_cast<uint32>(OptFlags::ALL))
    ThrowRDE("Invalid opt flags %x", optflags);
  _flags = static_cast<OptFlags>(optflags);

  startpump.getBits(8); // OverlapWidth
  startpump.getBits(8); // reserved
  startpump.getBits(8); // Inc
  startpump.getBits(2); // reserved
  initVal = startpump.getBits(14);

  if (width == 0 || height == 0 || width % 16 != 0 || width > 6496 ||
      height > 4336)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);

  if (width != static_cast<uint32>(mRaw->dim.x) ||
      height != static_cast<uint32>(mRaw->dim.y))
    ThrowRDE("EXIF image dimensions do not match dimensions from raw header");

  data = startpump.getStream(startpump.getRemainSize());
}

void SamsungV2Decompressor::decompress() {
  switch (_flags) {
  case OptFlags::NONE:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::NONE>(row);
    break;
  case OptFlags::ALL:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::ALL>(row);
    break;

  case OptFlags::SKIP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP>(row);
    break;
  case OptFlags::MV:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::MV>(row);
    break;
  case OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::QP>(row);
    break;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
  case OptFlags::SKIP | OptFlags::MV:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::MV>(row);
    break;
  case OptFlags::SKIP | OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::QP>(row);
    break;

  case OptFlags::MV | OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::MV | OptFlags::QP>(row);
    break;
#pragma GCC diagnostic pop

  default:
    __builtin_unreachable();
  }
}

template <SamsungV2Decompressor::OptFlags optflags>
void SamsungV2Decompressor::decompressRow(uint32 row) {
  // The format is relatively straightforward. Each line gets encoded as a set
  // of differences from pixels from another line. Pixels are grouped in blocks
  // of 16 (8 green, 8 red or blue). Each block is encoded in three sections.
  // First 1 or 4 bits to specify which reference pixels to use, then a section
  // that specifies for each pixel the number of bits in the difference, then
  // the actual difference bits

  // Align pump to 16byte boundary
  const auto line_offset = data.getPosition();
  if ((line_offset & 0xf) != 0)
    data.skipBytes(16 - (line_offset & 0xf));

  BitPumpMSB32 pump(data);

  auto* img = reinterpret_cast<ushort16*>(mRaw->getData(0, row));
  ushort16* img_up = reinterpret_cast<ushort16*>(
      mRaw->getData(0, std::max(0, static_cast<int>(row) - 1)));
  ushort16* img_up2 = reinterpret_cast<ushort16*>(
      mRaw->getData(0, std::max(0, static_cast<int>(row) - 2)));

  // Initialize the motion and diff modes at the start of the line
  uint32 motion = 7;
  // By default we are not scaling values at all
  int32 scale = 0;

  uint32 diffBitsMode[3][2] = {{0}};
  for (auto& i : diffBitsMode)
    i[0] = i[1] = (row == 0 || row == 1) ? 7 : 4;

  assert(width >= 16);
  assert(width % 16 == 0);
  for (uint32 col = 0; col < width; col += 16) {
    if (!(optflags & OptFlags::QP) && !(col & 63)) {
      static constexpr int32 scalevals[] = {0, -2, 2};
      uint32 i = pump.getBits(2);
      scale = i < 3 ? scale + scalevals[i] : pump.getBits(12);
    }

    // First we figure out which reference pixels mode we're in
    if (optflags & OptFlags::MV)
      motion = pump.getBits(1) ? 3 : 7;
    else if (!pump.getBits(1))
      motion = pump.getBits(3);

    if ((row == 0 || row == 1) && (motion != 7))
      ThrowRDE("At start of image and motion isn't 7. File corrupted?");

    if (motion == 7) {
      // The base case, just set all pixels to the previous ones on the same
      // line If we're at the left edge we just start at the initial value
      for (uint32 i = 0; i < 16; i++)
        img[i] = (col == 0) ? initVal : *(img + i - 2);
    } else {
      // The complex case, we now need to actually lookup one or two lines
      // above
      if (row < 2)
        ThrowRDE(
            "Got a previous line lookup on first two lines. File corrupted?");

      static constexpr int32 motionOffset[7] = {-4, -2, -2, 0, 0, 2, 4};
      static constexpr int32 motionDoAverage[7] = {0, 0, 1, 0, 1, 0, 0};

      int32 slideOffset = motionOffset[motion];
      int32 doAverage = motionDoAverage[motion];

      for (uint32 i = 0; i < 16; i++) {
        ushort16* line;
        ushort16* refpixel;

        if ((row + i) & 0x1) {
          // Red or blue pixels use same color two lines up
          line = img_up2;
          refpixel = line + i + slideOffset;
        } else {
          // Green pixel N uses Green pixel N from row above
          // (top left or top right)
          line = img_up;
          refpixel = line + i + slideOffset + (((i % 2) != 0) ? -1 : 1);
        }

        if (col == 0 && line > refpixel)
          ThrowRDE("Bad motion %u at the beginning of the row", motion);
        if (col + 16 == width && ((refpixel >= line + 16) ||
                                  (doAverage && (refpixel + 2 >= line + 16))))
          ThrowRDE("Bad motion %u at the end of the row", motion);

        // In some cases we use as reference interpolation of this pixel and
        // the next
        if (doAverage)
          img[i] = (*refpixel + *(refpixel + 2) + 1) >> 1;
        else
          img[i] = *refpixel;
      }
    }

    // Figure out how many difference bits we have to read for each pixel
    uint32 diffBits[4] = {0};
    if (optflags & OptFlags::SKIP || !pump.getBits(1)) {
      uint32 flags[4];
      for (unsigned int& flag : flags)
        flag = pump.getBits(2);

      for (uint32 i = 0; i < 4; i++) {
        // The color is 0-Green 1-Blue 2-Red
        uint32 colornum = (row % 2 != 0) ? i >> 1 : ((i >> 1) + 2) % 3;

        assert(flags[i] <= 3);
        switch (flags[i]) {
        case 0:
          diffBits[i] = diffBitsMode[colornum][0];
          break;
        case 1:
          diffBits[i] = diffBitsMode[colornum][0] + 1;
          break;
        case 2:
          diffBits[i] = diffBitsMode[colornum][0] - 1;
          break;
        case 3:
          diffBits[i] = pump.getBits(4);
          break;
        default:
          __builtin_unreachable();
        }

        diffBitsMode[colornum][0] = diffBitsMode[colornum][1];
        diffBitsMode[colornum][1] = diffBits[i];

        if (diffBits[i] > bitDepth + 1)
          ThrowRDE("Too many difference bits. File corrupted?");
      }
    }

    // Actually read the differences and write them to the pixels
    for (uint32 i = 0; i < 16; i++) {
      uint32 len = diffBits[i >> 2];
      int32 diff = pump.getBits(len);

      // If the first bit is 1 we need to turn this into a negative number
      if (len != 0 && diff >> (len - 1))
        diff -= (1 << len);

      ushort16* value = nullptr;
      // Apply the diff to pixels 0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
      if (row % 2)
        value = &img[((i & 0x7) << 1) + 1 - (i >> 3)];
      else
        value = &img[((i & 0x7) << 1) + (i >> 3)];

      diff = diff * (scale * 2 + 1) + scale;
      *value = clampBits(static_cast<int>(*value) + diff, bits);
    }

    img += 16;
    img_up += 16;
    img_up2 += 16;
  }

  data.skipBytes(pump.getBufferPosition());
}

} // namespace rawspeed
<|endoftext|>


<commit_before>/*
 * OjaConnProbe.cpp
 *
 *  Created on: Oct 15, 2012
 *      Author: dpaiton
 */

#include "OjaConnProbe.hpp"

namespace PV {

OjaConnProbe::OjaConnProbe() {
   initialize_base();
}

OjaConnProbe::OjaConnProbe(const char * probename, const char * filename, HyPerConn * conn, int postIndex)
{
   initialize_base();
   initialize(probename, filename, conn, INDEX_METHOD, postIndex, -1, -1, -1);
}

OjaConnProbe::OjaConnProbe(const char * probename, const char * filename, HyPerConn * conn, int kxPost, int kyPost, int kfPost)
{
   initialize_base();
   initialize(probename, filename, conn, COORDINATE_METHOD, -1, kxPost, kyPost, kfPost);
}

OjaConnProbe::~OjaConnProbe()
{
   free(preStdpTrs);
   free(preOjaTrs);
   free(preWeights);
}

int OjaConnProbe::initialize_base() {
   preStdpTrs = NULL;
   preOjaTrs  = NULL;
   preWeights = NULL;
   kPost      = -1;
   return PV_SUCCESS;
}

int OjaConnProbe::initialize(const char * probename, const char * filename,
      HyPerConn * conn, PatchIDMethod pidMethod, int postIndex,
      int kxPost, int kyPost, int kfPost)
{
   BaseConnectionProbe::initialize(probename, filename, conn);

   ojaConn = dynamic_cast<OjaSTDPConn *>(conn);
   assert(ojaConn != NULL);

   postLoc = ojaConn->postSynapticLayer()->getLayerLoc();

   int nxGlobal = postLoc->nxGlobal;
   int nyGlobal = postLoc->nyGlobal;
   int nf = postLoc->nf;
   int nb = postLoc->nb;
   int nxext = nxGlobal+2*nb;
   int nyext = nyGlobal+2*nb;

   if (pidMethod == INDEX_METHOD) {
      kPost = postIndex;
      kxPost = kxPos(kPost,nxext,nyext,nf)-nb;
      kyPost = kyPos(kPost,nxext,nyext,nf)-nb;
      kfPost = featureIndex(kPost,nxext,nyext,nf);
      //std::cout << "OjaConnProbe: kPost (INDEX): " << kPost << "\n";
   }
   else if(pidMethod == COORDINATE_METHOD) {
      assert(kfPost != 0); //TODO: Why does a single feature not have a kf of 0?
      kPost = kIndex(kxPost,kyPost,kfPost,postLoc->nx,postLoc->ny,postLoc->nf);// nx, ny, nf NOT in extended space
      //std::cout << "OjaConnProbe: kPost (COORDINATE): " << kPost << "\n";
   }
   else assert(false);
   assert(kPost != -1);

// Now convert from global coordinates to local coordinates
   int kxPostLocal = kxPost - postLoc->kx0;
   int kyPostLocal = kyPost - postLoc->ky0;
   int nxLocal = postLoc->nx;
   int nyLocal = postLoc->ny;
   int kLocal = kIndex(kxPostLocal+nb,kyPostLocal+nb,kfPost,nxLocal+2*nb,nyLocal+2*nb,nf);
   assert(kLocal >=0 && kLocal < ojaConn->postSynapticLayer()->getNumExtended());

   int inbounds = kxPostLocal < -nb || kxPostLocal > postLoc->nx+nb || kyPostLocal < -nb || kyPostLocal > postLoc->ny+nb;

   if(inbounds) {
      FILE * fp = getFilePtr();
      fprintf(fp, "Rank %d process is in bounds for index %d, x=%d, y=%d, f=%d\n", 0, kPost, kxPost, kyPost, kfPost);
      std::cout << "in bounds!\n";
   }
   else
   {
      assert(false);
   }

   return PV_SUCCESS;
}

int OjaConnProbe::outputState(float timef)
{
   // Get post layer sizes
   int nxpPost = ojaConn->getNxpPost();
   int nypPost = ojaConn->getNypPost();
   int nfpPost = ojaConn->getNfpPost();

   int numArbors = ojaConn->numberOfAxonalArborLists(); //will loop through arbors
   int numPostPOVPatch = nxpPost * nypPost * nfpPost; // Post-synaptic weights are never shrunken

//   std::cout << "OjaConnProbe: numArbors: " << numArbors << "\n";
//   std::cout << "OjaConnProbe: numPostPOVPatch: " << numPostPOVPatch << "\n";

   // Allocate buffers for pre info
   preStdpTrs = (float *) calloc(numPostPOVPatch*numArbors, sizeof(float));
   preOjaTrs  = (float *) calloc(numPostPOVPatch*numArbors, sizeof(float));
   preWeights = (float *) calloc(numPostPOVPatch*numArbors, sizeof(float));
   assert(preStdpTrs != NULL);
   assert(preOjaTrs != NULL);
   assert(preWeights != NULL);

   const PVLayerLoc * preLoc  = ojaConn->preSynapticLayer()->getLayerLoc(); //need pre layer sizes for patch index info

   int preTraceIdx = 0;
   for (int arborID=0; arborID < numArbors; arborID++)
   {
      postWeights = ojaConn->getPostWeights(arborID,kPost); // Pointer array full of addresses pointing to the weights for all of the preNeurons connected to the given postNeuron's receptive field
      float * startAdd = ojaConn->get_wDataStart(arborID);                    // Address of first preNeuron in pre layer
      for (int preNeuronID=0; preNeuronID<numPostPOVPatch; preNeuronID++)
      {
         float * kPreAdd = postWeights[preNeuronID];                             // Address of first preNeuron in receptive field of postNeuron
         int kPre = (kPreAdd-startAdd) / (preLoc->nx * preLoc->ny * preLoc->nf); // Specific preNeuron's (extended) index

         assert(preTraceIdx < numArbors*numPostPOVPatch);
         preWeights[preTraceIdx] = *(postWeights[preNeuronID]); // One weight per arbor per preNeuron in postNeuron's receptive field
         preStdpTrs[preTraceIdx] = ojaConn->getPreStdpTr(kPre); // Trace with STDP-related time scale (tauLTD)
         preOjaTrs[preTraceIdx]  = ojaConn->getPreOjaTr(kPre);  // Trace with Oja-related time scale (tauOja)
         preTraceIdx++;
      }
   }

   postStdpTr  = ojaConn->getPostStdpTr(kPost);
   postOjaTr   = ojaConn->getPostOjaTr(kPost);
   postIntTr   = ojaConn->getPostIntTr(kPost);
   ampLTD      = ojaConn->getAmpLTD(kPost);

   // Write out to file
   FILE * fp = getFilePtr();
   assert(fp);

   const char * msg = getName(); // Message to precede the probe's output line

   fprintf(fp, "%s:      t=%.1f kPost=%d", msg, timef, kPost);
   fprintf(fp, " poStdpTr=%-6.3f",postStdpTr);
   fprintf(fp, " poOjaTr=%-6.3f",postOjaTr);
   fprintf(fp, " poIntTr=%-6.3f",postIntTr);
   fprintf(fp, " ampLTD=%-6.3f",ampLTD);
   for (int weightIdx=0; weightIdx < numArbors*numPostPOVPatch; weightIdx++) {
      fprintf(fp, " prStdpTr%d=%-6.3f",weightIdx,preStdpTrs[weightIdx]);
      fprintf(fp, " prOjaTr%d=%-6.3f",weightIdx,preOjaTrs[weightIdx]);
      fprintf(fp, " weights%d=%-6.3f",weightIdx,preWeights[weightIdx]);
   }
   fprintf(fp, "\n");
   fflush(fp);

   return PV_SUCCESS;
}
} //end of namespacePV

<commit_msg>OjaConnProbe bugfixes attending to local vs. global and restricted vs. extended<commit_after>/*
 * OjaConnProbe.cpp
 *
 *  Created on: Oct 15, 2012
 *      Author: dpaiton
 */

#include "OjaConnProbe.hpp"

namespace PV {

OjaConnProbe::OjaConnProbe() {
   initialize_base();
}

OjaConnProbe::OjaConnProbe(const char * probename, const char * filename, HyPerConn * conn, int postIndex)
{
   initialize_base();
   initialize(probename, filename, conn, INDEX_METHOD, postIndex, -1, -1, -1);
}

OjaConnProbe::OjaConnProbe(const char * probename, const char * filename, HyPerConn * conn, int kxPost, int kyPost, int kfPost)
{
   initialize_base();
   initialize(probename, filename, conn, COORDINATE_METHOD, -1, kxPost, kyPost, kfPost);
}

OjaConnProbe::~OjaConnProbe()
{
   free(preStdpTrs);
   free(preOjaTrs);
   free(preWeights);
}

int OjaConnProbe::initialize_base() {
   preStdpTrs = NULL;
   preOjaTrs  = NULL;
   preWeights = NULL;
   kPost      = -1;
   return PV_SUCCESS;
}

int OjaConnProbe::initialize(const char * probename, const char * filename,
      HyPerConn * conn, PatchIDMethod pidMethod, int postIndex,
      int kxPost, int kyPost, int kfPost)
{
   BaseConnectionProbe::initialize(probename, filename, conn);

   ojaConn = dynamic_cast<OjaSTDPConn *>(conn);
   assert(ojaConn != NULL);

   postLoc = ojaConn->postSynapticLayer()->getLayerLoc();

   int nxGlobal = postLoc->nxGlobal;
   int nyGlobal = postLoc->nyGlobal;
   int nf = postLoc->nf;
   int nb = postLoc->nb;
   int nxext = nxGlobal+2*nb;
   int nyext = nyGlobal+2*nb;

   if (pidMethod == INDEX_METHOD) {
      kPost = postIndex;
      kxPost = kxPos(kPost,nxGlobal,nyGlobal,nf);
      kyPost = kyPos(kPost,nxGlobal,nyGlobal,nf);
      kfPost = featureIndex(kPost,nxGlobal,nyGlobal,nf);
      //std::cout << "OjaConnProbe: kPost (INDEX): " << kPost << "\n";
   }
   else if(pidMethod == COORDINATE_METHOD) {
      // assert(kfPost != 0); //TODO: Why does a single feature not have a kf of 0?
      kPost = kIndex(kxPost,kyPost,kfPost,nxGlobal,nyGlobal,nf); // nx, ny, nf NOT in extended space
      //std::cout << "OjaConnProbe: kPost (COORDINATE): " << kPost << "\n";
   }
   else assert(false);
   assert(kPost != -1);

// Now convert from global coordinates to local coordinates
   int kxPostLocal = kxPost - postLoc->kx0;
   int kyPostLocal = kyPost - postLoc->ky0;
   int nxLocal = postLoc->nx;
   int nyLocal = postLoc->ny;
   int kLocal = kIndex(kxPostLocal,kyPostLocal,kfPost,nxLocal,nyLocal,nf);
   // assert(kLocal >=0 && kLocal < ojaConn->postSynapticLayer()->getNumExtended());

   int inbounds = !(kxPostLocal < 0 || kxPostLocal >= postLoc->nx || kyPostLocal < 0 || kyPostLocal >= postLoc->ny);

   if(inbounds) {
      FILE * fp = getFilePtr();
      fprintf(fp, "Rank %d process is in bounds for index %d, x=%d, y=%d, f=%d\n", 0, kPost, kxPost, kyPost, kfPost);
      std::cout << "in bounds!\n";
   }
   else
   {
      assert(false);
   }

   return PV_SUCCESS;
}

int OjaConnProbe::outputState(float timef)
{
   // Get post layer sizes
   int nxpPost = ojaConn->getNxpPost();
   int nypPost = ojaConn->getNypPost();
   int nfpPost = ojaConn->getNfpPost();

   int numArbors = ojaConn->numberOfAxonalArborLists(); //will loop through arbors
   int numPostPOVPatch = nxpPost * nypPost * nfpPost; // Post-synaptic weights are never shrunken

//   std::cout << "OjaConnProbe: numArbors: " << numArbors << "\n";
//   std::cout << "OjaConnProbe: numPostPOVPatch: " << numPostPOVPatch << "\n";

   // Allocate buffers for pre info
   preStdpTrs = (float *) calloc(numPostPOVPatch*numArbors, sizeof(float));
   preOjaTrs  = (float *) calloc(numPostPOVPatch*numArbors, sizeof(float));
   preWeights = (float *) calloc(numPostPOVPatch*numArbors, sizeof(float));
   assert(preStdpTrs != NULL);
   assert(preOjaTrs != NULL);
   assert(preWeights != NULL);

   const PVLayerLoc * preLoc  = ojaConn->preSynapticLayer()->getLayerLoc(); //need pre layer sizes for patch index info

   int preTraceIdx = 0;
   for (int arborID=0; arborID < numArbors; arborID++)
   {
      postWeights = ojaConn->getPostWeights(arborID,kPost); // Pointer array full of addresses pointing to the weights for all of the preNeurons connected to the given postNeuron's receptive field
      float * startAdd = ojaConn->get_wDataStart(arborID);                    // Address of first preNeuron in pre layer
      for (int preNeuronID=0; preNeuronID<numPostPOVPatch; preNeuronID++)
      {
         float * kPreAdd = postWeights[preNeuronID];                             // Address of first preNeuron in receptive field of postNeuron
         int kPre = (kPreAdd-startAdd) / (preLoc->nx * preLoc->ny * preLoc->nf); // Specific preNeuron's (extended) index

         assert(preTraceIdx < numArbors*numPostPOVPatch);
         preWeights[preTraceIdx] = *(postWeights[preNeuronID]); // One weight per arbor per preNeuron in postNeuron's receptive field
         preStdpTrs[preTraceIdx] = ojaConn->getPreStdpTr(kPre); // Trace with STDP-related time scale (tauLTD)
         preOjaTrs[preTraceIdx]  = ojaConn->getPreOjaTr(kPre);  // Trace with Oja-related time scale (tauOja)
         preTraceIdx++;
      }
   }

   postStdpTr  = ojaConn->getPostStdpTr(kPost);
   postOjaTr   = ojaConn->getPostOjaTr(kPost);
   postIntTr   = ojaConn->getPostIntTr(kPost);
   ampLTD      = ojaConn->getAmpLTD(kPost);

   // Write out to file
   FILE * fp = getFilePtr();
   assert(fp);

   const char * msg = getName(); // Message to precede the probe's output line

   fprintf(fp, "%s:      t=%.1f kPost=%d", msg, timef, kPost);
   fprintf(fp, " poStdpTr=%-6.3f",postStdpTr);
   fprintf(fp, " poOjaTr=%-6.3f",postOjaTr);
   fprintf(fp, " poIntTr=%-6.3f",postIntTr);
   fprintf(fp, " ampLTD=%-6.3f",ampLTD);
   for (int weightIdx=0; weightIdx < numArbors*numPostPOVPatch; weightIdx++) {
      fprintf(fp, " prStdpTr%d=%-6.3f",weightIdx,preStdpTrs[weightIdx]);
      fprintf(fp, " prOjaTr%d=%-6.3f",weightIdx,preOjaTrs[weightIdx]);
      fprintf(fp, " weights%d=%-6.3f",weightIdx,preWeights[weightIdx]);
   }
   fprintf(fp, "\n");
   fflush(fp);

   return PV_SUCCESS;
}
} //end of namespacePV

<|endoftext|>


<commit_before><commit_msg>Updated exporter to emit for all methods<commit_after><|endoftext|>


<commit_before>#ifndef __coldata3_hh__
#define __coldata3_hh__
#ifdef __WIN32__
#include <Windows32/Base.h>
#include <Windows32/Defines.h>
#include <Windows32/Structures.h>
#include <winsock.h>
#define errno WSAGetLastError()
#endif
#include <mysql.h>
#include <string>
#include "coldata2.hh"
#include "convert3.hh"
#include "null3.hh"

template <class Str> template <class T, class B>
mysql_ColData<Str>::operator Null<T,B> () const {
  if ((*this)[0] == 'N' && (*this)[1] == 'U' &&
      (*this)[2] == 'U' && (*this)[3] == 'L' && size() == 4)
    return Null<T,B>(null);
  else return Null<T,B>(conv(T()));
}

#endif
<commit_msg>Attempt at fixing reported GCC 3.4 bugs due to increased pedantry.  Not tested since I don't have a machine with GCC 3.4 yet, but it doesn't break on 3.2, so....<commit_after>#ifndef __coldata3_hh__
#define __coldata3_hh__
#ifdef __WIN32__
#include <Windows32/Base.h>
#include <Windows32/Defines.h>
#include <Windows32/Structures.h>
#include <winsock.h>
#define errno WSAGetLastError()
#endif
#include <mysql.h>
#include <string>
#include "coldata2.hh"
#include "convert3.hh"
#include "null3.hh"

template <class Str> template <class T, class B>
mysql_ColData<Str>::operator Null<T,B> () const {
  if ((*this)[0] == 'N' && (*this)[1] == 'U' &&
      (*this)[2] == 'U' && (*this)[3] == 'L' && Str::size() == 4)
    return Null<T,B>(null);
  else return Null<T,B>(conv(T()));
}

#endif
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file Style.cxx
 ** Defines the font and colour style for a class of text.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "Style.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

FontAlias::FontAlias() {
}

FontAlias::~FontAlias() {
	SetID(0);
	// ~Font will not release the actual font resource sine it is now 0
}

void FontAlias::MakeAlias(Font &fontOrigin) {
	SetID(fontOrigin.GetID());
}

void FontAlias::ClearFont() {
	SetID(0);
}

bool FontSpecification::EqualTo(const FontSpecification &other) const {
	return bold == other.bold &&
	       italic == other.italic &&
	       size == other.size &&
	       characterSet == other.characterSet &&
	       fontName == other.fontName;
}

FontMeasurements::FontMeasurements() {
	Clear();
}

void FontMeasurements::Clear() {
	lineHeight = 2;
	ascent = 1;
	descent = 1;
	externalLeading = 0;
	aveCharWidth = 1;
	spaceWidth = 1;
	sizeZoomed = 2;
}

Style::Style() {
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      Platform::DefaultFontSize(), 0, SC_CHARSET_DEFAULT,
	      false, false, false, false, caseMixed, true, true, false);
}

Style::Style(const Style &source) {
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      0, 0, 0,
	      false, false, false, false, caseMixed, true, true, false);
	fore.desired = source.fore.desired;
	back.desired = source.back.desired;
	characterSet = source.characterSet;
	bold = source.bold;
	italic = source.italic;
	size = source.size;
	eolFilled = source.eolFilled;
	underline = source.underline;
	caseForce = source.caseForce;
	visible = source.visible;
	changeable = source.changeable;
	hotspot = source.hotspot;
}

Style::~Style() {
}

Style &Style::operator=(const Style &source) {
	if (this == &source)
		return * this;
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      0, 0, SC_CHARSET_DEFAULT,
	      false, false, false, false, caseMixed, true, true, false);
	fore.desired = source.fore.desired;
	back.desired = source.back.desired;
	characterSet = source.characterSet;
	bold = source.bold;
	italic = source.italic;
	size = source.size;
	eolFilled = source.eolFilled;
	underline = source.underline;
	caseForce = source.caseForce;
	visible = source.visible;
	changeable = source.changeable;
	return *this;
}

void Style::Clear(ColourDesired fore_, ColourDesired back_, int size_,
        const char *fontName_, int characterSet_,
        bool bold_, bool italic_, bool eolFilled_,
        bool underline_, ecaseForced caseForce_,
        bool visible_, bool changeable_, bool hotspot_) {
	fore.desired = fore_;
	back.desired = back_;
	characterSet = characterSet_;
	bold = bold_;
	italic = italic_;
	size = size_;
	fontName = fontName_;
	eolFilled = eolFilled_;
	underline = underline_;
	caseForce = caseForce_;
	visible = visible_;
	changeable = changeable_;
	hotspot = hotspot_;
	font.ClearFont();
	FontMeasurements::Clear();
}

void Style::ClearTo(const Style &source) {
	Clear(
	    source.fore.desired,
	    source.back.desired,
	    source.size,
	    source.fontName,
	    source.characterSet,
	    source.bold,
	    source.italic,
	    source.eolFilled,
	    source.underline,
	    source.caseForce,
	    source.visible,
	    source.changeable,
	    source.hotspot);
}

void Style::Copy(Font &font_, const FontMeasurements &fm_) {
	font.MakeAlias(font_);
	(FontMeasurements &)(*this) = fm_;
#if PLAT_WX
	ascent = surface.Ascent(font);
#endif
}
<commit_msg>Code for wxWidgets did not compile so removing.<commit_after>// Scintilla source code edit control
/** @file Style.cxx
 ** Defines the font and colour style for a class of text.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "Style.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

FontAlias::FontAlias() {
}

FontAlias::~FontAlias() {
	SetID(0);
	// ~Font will not release the actual font resource sine it is now 0
}

void FontAlias::MakeAlias(Font &fontOrigin) {
	SetID(fontOrigin.GetID());
}

void FontAlias::ClearFont() {
	SetID(0);
}

bool FontSpecification::EqualTo(const FontSpecification &other) const {
	return bold == other.bold &&
	       italic == other.italic &&
	       size == other.size &&
	       characterSet == other.characterSet &&
	       fontName == other.fontName;
}

FontMeasurements::FontMeasurements() {
	Clear();
}

void FontMeasurements::Clear() {
	lineHeight = 2;
	ascent = 1;
	descent = 1;
	externalLeading = 0;
	aveCharWidth = 1;
	spaceWidth = 1;
	sizeZoomed = 2;
}

Style::Style() {
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      Platform::DefaultFontSize(), 0, SC_CHARSET_DEFAULT,
	      false, false, false, false, caseMixed, true, true, false);
}

Style::Style(const Style &source) {
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      0, 0, 0,
	      false, false, false, false, caseMixed, true, true, false);
	fore.desired = source.fore.desired;
	back.desired = source.back.desired;
	characterSet = source.characterSet;
	bold = source.bold;
	italic = source.italic;
	size = source.size;
	eolFilled = source.eolFilled;
	underline = source.underline;
	caseForce = source.caseForce;
	visible = source.visible;
	changeable = source.changeable;
	hotspot = source.hotspot;
}

Style::~Style() {
}

Style &Style::operator=(const Style &source) {
	if (this == &source)
		return * this;
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      0, 0, SC_CHARSET_DEFAULT,
	      false, false, false, false, caseMixed, true, true, false);
	fore.desired = source.fore.desired;
	back.desired = source.back.desired;
	characterSet = source.characterSet;
	bold = source.bold;
	italic = source.italic;
	size = source.size;
	eolFilled = source.eolFilled;
	underline = source.underline;
	caseForce = source.caseForce;
	visible = source.visible;
	changeable = source.changeable;
	return *this;
}

void Style::Clear(ColourDesired fore_, ColourDesired back_, int size_,
        const char *fontName_, int characterSet_,
        bool bold_, bool italic_, bool eolFilled_,
        bool underline_, ecaseForced caseForce_,
        bool visible_, bool changeable_, bool hotspot_) {
	fore.desired = fore_;
	back.desired = back_;
	characterSet = characterSet_;
	bold = bold_;
	italic = italic_;
	size = size_;
	fontName = fontName_;
	eolFilled = eolFilled_;
	underline = underline_;
	caseForce = caseForce_;
	visible = visible_;
	changeable = changeable_;
	hotspot = hotspot_;
	font.ClearFont();
	FontMeasurements::Clear();
}

void Style::ClearTo(const Style &source) {
	Clear(
	    source.fore.desired,
	    source.back.desired,
	    source.size,
	    source.fontName,
	    source.characterSet,
	    source.bold,
	    source.italic,
	    source.eolFilled,
	    source.underline,
	    source.caseForce,
	    source.visible,
	    source.changeable,
	    source.hotspot);
}

void Style::Copy(Font &font_, const FontMeasurements &fm_) {
	font.MakeAlias(font_);
	(FontMeasurements &)(*this) = fm_;
}
<|endoftext|>


<commit_before>/* TMP36 library

 Copyright 2017 Isaac100

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

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

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

 This library converts the analog values from a TMP36 temperature
 sensor directly into Celcius and Fahrenheit so you don't have to.
 */

#include "Arduino.h"
#include "TMP36.h"

TMP36::TMP36(uint8_t pin) {
 pinMode(pin, INPUT);
 _pin = pin;
}

void TMP36::getValues() {
 _value = analogRead(_pin);
 _voltage = (_value/1024.0) * 5.0;
 _tempC = (_voltage - .5) * 100;
 _tempF = (_tempC * 1.8) + 32;
}

float TMP36::getVoltage() {
 getValues();
 return _voltage;
}

float TMP36::getTempC() {
 getValues();
 return _tempC;
}

float TMP36::getTempF() {
 getValues();
 return _tempF;
}

<commit_msg>Update TMP36.cpp<commit_after>/* TMP36 library

 Copyright 2017 Isaac100

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

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

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

 This library converts the analog values from a TMP36 temperature
 sensor directly into Celcius and Fahrenheit so you don't have to.
 */

#include "Arduino.h"
#include "TMP36.h"

TMP36::TMP36(uint8_t pin, float aref) {
 pinMode(pin, INPUT);
 _aref = aref
 _pin = pin;
}

void TMP36::getValues() {
 _value = analogRead(_pin);
 _voltage = (_value/1024.0) * _aref;
 _tempC = (_voltage - .5) * 100;
 _tempF = (_tempC * 1.8) + 32;
}

float TMP36::getVoltage() {
 getValues();
 return _voltage;
}

float TMP36::getTempC() {
 getValues();
 return _tempC;
}

float TMP36::getTempF() {
 getValues();
 return _tempF;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
//     Free Software Foundation, Inc.,
//     51 Franklin Street, Fifth Floor,
//     Boston, MA
//     02110-1301
//     USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <iomanip>
#include <sstream>
#include "Timer.h"
#include "Context.h"

extern Context context;

////////////////////////////////////////////////////////////////////////////////
// Timer starts when the object is constructed.
Timer::Timer (const std::string& description)
: mDescription (description)
{
  ::gettimeofday (&mStart, NULL);
}

////////////////////////////////////////////////////////////////////////////////
// Timer stops when the object is destructed.
Timer::~Timer ()
{
  struct timeval end;
  ::gettimeofday (&end, NULL);

  std::stringstream s;
  s << "Timer " // No i18n
    << mDescription
    << " "
    << std::setprecision (6)
    << ((end.tv_sec - mStart.tv_sec) + ((end.tv_usec - mStart.tv_usec )
       / 1000000.0));

  context.debug (s.str ());
}

////////////////////////////////////////////////////////////////////////////////

<commit_msg>Enhancement - timers<commit_after>////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
//     Free Software Foundation, Inc.,
//     51 Franklin Street, Fifth Floor,
//     Boston, MA
//     02110-1301
//     USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <iomanip>
#include <sstream>
#include "Timer.h"
#include "Context.h"

extern Context context;

////////////////////////////////////////////////////////////////////////////////
// Timer starts when the object is constructed.
Timer::Timer (const std::string& description)
: mDescription (description)
{
  ::gettimeofday (&mStart, NULL);
}

////////////////////////////////////////////////////////////////////////////////
// Timer stops when the object is destructed.
Timer::~Timer ()
{
  struct timeval end;
  ::gettimeofday (&end, NULL);

  std::stringstream s;
  s << "Timer " // No i18n
    << mDescription
    << " "
    << std::setprecision (6)
    << std::fixed
    << ((end.tv_sec - mStart.tv_sec) + ((end.tv_usec - mStart.tv_usec )
       / 1000000.0));

  context.debug (s.str ());
}

////////////////////////////////////////////////////////////////////////////////

<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osgUtil/RenderLeaf>
#include <osgUtil/RenderGraph>

using namespace osg;
using namespace osgUtil;

// comment if you are are working with vertex programs,
// but it does break osgreflect demo and perhaps others, so keep an eye
// out artifacts.
// #define APPLY_MATICES_BEFORE_STATE

void RenderLeaf::render(State& state,RenderLeaf* previous)
{

    if (previous)
    {

#ifdef APPLY_MATICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif
        // apply state if required.
        RenderGraph* prev_rg = previous->_parent;
        RenderGraph* prev_rg_parent = prev_rg->_parent;
        RenderGraph* rg = _parent;
        if (prev_rg_parent!=rg->_parent)
        {
            RenderGraph::moveRenderGraph(state,prev_rg_parent,rg->_parent);

            // send state changes and matrix changes to OpenGL.
            state.apply(rg->_stateset.get());

        }
        else if (rg!=prev_rg)
        {

            // send state changes and matrix changes to OpenGL.
            state.apply(rg->_stateset.get());

        }

#ifndef APPLY_MATICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // draw the drawable
        _drawable->draw(state);
    }
    else
    {
#ifdef APPLY_MATICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // apply state if required.
         RenderGraph::moveRenderGraph(state,NULL,_parent->_parent);

        state.apply(_parent->_stateset.get());

#ifndef APPLY_MATICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // draw the drawable
        _drawable->draw(state);
    }
}
<commit_msg>Fixed typo of APPLY_MATICES_BEFORE_STATE.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osgUtil/RenderLeaf>
#include <osgUtil/RenderGraph>

using namespace osg;
using namespace osgUtil;

// comment if you are are working with vertex programs,
// but it does break osgreflect demo and perhaps others, so keep an eye
// out artifacts.
// #define APPLY_MATRICES_BEFORE_STATE

void RenderLeaf::render(State& state,RenderLeaf* previous)
{

    if (previous)
    {

#ifdef APPLY_MATRICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif
        // apply state if required.
        RenderGraph* prev_rg = previous->_parent;
        RenderGraph* prev_rg_parent = prev_rg->_parent;
        RenderGraph* rg = _parent;
        if (prev_rg_parent!=rg->_parent)
        {
            RenderGraph::moveRenderGraph(state,prev_rg_parent,rg->_parent);

            // send state changes and matrix changes to OpenGL.
            state.apply(rg->_stateset.get());

        }
        else if (rg!=prev_rg)
        {

            // send state changes and matrix changes to OpenGL.
            state.apply(rg->_stateset.get());

        }

#ifndef APPLY_MATRICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // draw the drawable
        _drawable->draw(state);
    }
    else
    {
#ifdef APPLY_MATRICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // apply state if required.
         RenderGraph::moveRenderGraph(state,NULL,_parent->_parent);

        state.apply(_parent->_stateset.get());

#ifndef APPLY_MATRICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // draw the drawable
        _drawable->draw(state);
    }
}
<|endoftext|>