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

#include <modules/eigenutils/processors/testmatrix.h>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo TestMatrix::processorInfo_{
    "org.inviwo.TestMatrix",      // Class identifier
    "Test Matrix",                // Display name
    "Undefined",              // Category
    CodeState::Experimental,  // Code state
    Tags::None,               // Tags
};
const ProcessorInfo TestMatrix::getProcessorInfo() const { return processorInfo_; }

TestMatrix::TestMatrix()
    : Processor()
    , matrix_("matrix_")
    , size_("size","Matrix size (square)" , 10 , 1 , 1000)
{
    addPort(matrix_);
    addProperty(size_);
}

void TestMatrix::process() {

    auto m = std::make_shared<Eigen::MatrixXf>(size_.get(),size_.get());
    for(int y = 0;y<size_.get();y++){
        float Y = y / static_cast<float>(size_.get()-1);
        Y *= Y * 0.5f;
        for(int x = 0;x<size_.get();x++){
            float X = x / static_cast<float>(size_.get()-1);
            X *= X;
            (*m)(y,x) = glm::mix( Y , 1.0f , X);
        }
    }
    matrix_.setData(m);
}

}  // namespace inviwo
<commit_msg>Eigen: Clang-format and processorInfo_ update<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/eigenutils/processors/testmatrix.h>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo TestMatrix::processorInfo_{
    "org.inviwo.TestMatrix",  // Class identifier
    "Test Matrix",            // Display name
    "Eigen",                  // Category
    CodeState::Stable,        // Code state
    "Testing",                // Tags
};
const ProcessorInfo TestMatrix::getProcessorInfo() const { return processorInfo_; }

TestMatrix::TestMatrix()
    : Processor(), matrix_("matrix_"), size_("size", "Matrix size (square)", 10, 1, 1000) {
    addPort(matrix_);
    addProperty(size_);
}

void TestMatrix::process() {

    auto m = std::make_shared<Eigen::MatrixXf>(size_.get(), size_.get());
    for (int y = 0; y < size_.get(); y++) {
        float Y = y / static_cast<float>(size_.get() - 1);
        Y *= Y * 0.5f;
        for (int x = 0; x < size_.get(); x++) {
            float X = x / static_cast<float>(size_.get() - 1);
            X *= X;
            (*m)(y, x) = glm::mix(Y, 1.0f, X);
        }
    }
    matrix_.setData(m);
}

}  // namespace inviwo
<|endoftext|>


<commit_before>// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation

#ifndef OPENCV_GAPI_OWN_ASSERT_HPP
#define OPENCV_GAPI_OWN_ASSERT_HPP

#if !defined(GAPI_STANDALONE)
#include <opencv2/core/base.hpp>
#define GAPI_Assert CV_Assert
#define GAPI_DbgAssert CV_DbgAssert

#else
#include <stdexcept>
#include <sstream>
#include <opencv2/gapi/util/throw.hpp>

namespace detail
{
    inline void assert_abort(const char* str, int line, const char* file, const char* func)
    {
        std::stringstream ss;
        ss << file << ":" << line << ": Assertion " << str << " in function " << func << " failed\n";
        cv::util::throw_error(std::logic_error(ss.str()));
    }
}

#define GAPI_Assert(expr) \
{ if (!(expr)) ::detail::assert_abort(#expr, __LINE__, __FILE__, __func__); }

#ifdef NDEBUG
#  define GAPI_DbgAssert(expr)
#else
#  define GAPI_DbgAssert(expr) GAPI_Assert(expr)
#endif

#endif // GAPI_STANDALONE

#endif // OPENCV_GAPI_OWN_ASSERT_HPP
<commit_msg>GAPI: Fix [-Wreturn-type] warning on standalone mac build<commit_after>// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation

#ifndef OPENCV_GAPI_OWN_ASSERT_HPP
#define OPENCV_GAPI_OWN_ASSERT_HPP

#if !defined(GAPI_STANDALONE)
#include <opencv2/core/base.hpp>
#define GAPI_Assert CV_Assert
#define GAPI_DbgAssert CV_DbgAssert

#else
#include <stdexcept>
#include <sstream>
#include <opencv2/gapi/util/throw.hpp>

namespace detail
{
    [[noreturn]] inline void assert_abort(const char* str, int line, const char* file, const char* func)
    {
        std::stringstream ss;
        ss << file << ":" << line << ": Assertion " << str << " in function " << func << " failed\n";
        cv::util::throw_error(std::logic_error(ss.str()));
    }
}

#define GAPI_Assert(expr) \
{ if (!(expr)) ::detail::assert_abort(#expr, __LINE__, __FILE__, __func__); }

#ifdef NDEBUG
#  define GAPI_DbgAssert(expr)
#else
#  define GAPI_DbgAssert(expr) GAPI_Assert(expr)
#endif

#endif // GAPI_STANDALONE

#endif // OPENCV_GAPI_OWN_ASSERT_HPP
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// 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.                                           //
// ======================================================================== //

// mpiCommon
#include "mpiCommon/MPICommon.h"
// public-ospray
#include "ospray/ospray_cpp/Camera.h"
#include "ospray/ospray_cpp/Data.h"
#include "ospray/ospray_cpp/Device.h"
#include "ospray/ospray_cpp/FrameBuffer.h"
#include "ospray/ospray_cpp/Renderer.h"
#include "ospray/ospray_cpp/TransferFunction.h"
#include "ospray/ospray_cpp/Volume.h"
// ospray apps
#include "common/commandline/CameraParser.h"
#include "widgets/imguiViewer.h"
// stl
#include <random>

#define RUN_LOCAL 0

namespace ospRandSphereTest {

  using namespace ospcommon;

  int   numSpheresPerNode = 100;
  float sphereRadius      = 0.01f;
  float sceneLowerBound   = 0.f;
  float sceneUpperBound   = 1.f;
  vec2i fbSize            = vec2i(1024, 768);
  int   numFrames         = 32;
  bool  runDistributed    = true;
  bool  withVolume        = false;

  //TODO: factor this into a reusable piece inside of ospcommon!!!!!!
  // helper function to write the rendered image as PPM file
  void writePPM(const std::string &fileName,
                const int sizeX, const int sizeY,
                const uint32_t *pixel)
  {
    FILE *file = fopen(fileName.c_str(), "wb");
    fprintf(file, "P6\n%i %i\n255\n", sizeX, sizeY);
    unsigned char *out = (unsigned char *)alloca(3*sizeX);
    for (int y = 0; y < sizeY; y++) {
      auto *in = (const unsigned char *)&pixel[(sizeY-1-y)*sizeX];
      for (int x = 0; x < sizeX; x++) {
        out[3*x + 0] = in[4*x + 0];
        out[3*x + 1] = in[4*x + 1];
        out[3*x + 2] = in[4*x + 2];
      }
      fwrite(out, 3*sizeX, sizeof(char), file);
    }
    fprintf(file, "\n");
    fclose(file);
  }

  std::pair<ospray::cpp::Geometry, box3f> makeSpheres()
  {
    struct Sphere
    {
      vec3f org;
      int colorID {0};
    };

    std::vector<Sphere> spheres(numSpheresPerNode);

    std::mt19937 rng;
    rng.seed(std::random_device()());
    std::uniform_real_distribution<float> dist(sceneLowerBound,
                                               sceneUpperBound);

    for (auto &s : spheres) {
      s.org.x = dist(rng);
      s.org.y = dist(rng);
      s.org.z = dist(rng);
    }

    ospray::cpp::Data sphere_data(numSpheresPerNode * sizeof(Sphere),
                                  OSP_UCHAR, spheres.data());

    auto numRanks = static_cast<float>(mpicommon::numGlobalRanks());
    auto myRank   = mpicommon::globalRank();

#if 1
    float r = (numRanks - myRank) / numRanks;
    float b = myRank / numRanks;
    float g = myRank > numRanks / 2 ? 2 * r : 2 * b;
#else
    float normRank = myRank / numRanks;
    float r = 2 * (1.f - normRank - 0.5f);
    if (r < 0.f) r = 0.f;
    float b = 2 * (normRank - 0.5f);
    if (b < 0.f) b = 0.f;
    float g = myRank < numRanks / 2 ? 1.f - r : 1.f - b;
    g *= 0.5f;
#endif

    vec4f color(r, g, b, 1.f);

    ospray::cpp::Data color_data(1, OSP_FLOAT4, &color);

    ospray::cpp::Geometry geom("spheres");
    geom.set("spheres", sphere_data);
    geom.set("color", color_data);
    geom.set("offset_colorID", int(sizeof(vec3f)));
    geom.set("radius", sphereRadius);
    geom.commit();

    //NOTE: all ranks will have the same bounding box, no matter what spheres
    //      were randomly generated
    auto bbox = box3f(vec3f(sceneLowerBound), vec3f(sceneUpperBound));

    return std::make_pair(geom, bbox);
  }

  std::pair<ospray::cpp::Volume, box3f> makeVolume()
  {
    auto numRanks = static_cast<float>(mpicommon::numGlobalRanks());
    auto myRank   = mpicommon::globalRank();

    ospray::cpp::TransferFunction transferFcn("piecewise_linear");
    const std::vector<vec3f> colors = {
      vec3f(0.231373, 0.298039 , 0.75294),
      vec3f(0.865003, 0.865003 , 0.86500),
      vec3f(0.705882, 0.0156863, 0.14902)
    };
    const std::vector<float> opacities = {0.05, 0.1};
    ospray::cpp::Data colorsData(colors.size(), OSP_FLOAT3, colors.data());
    ospray::cpp::Data opacityData(opacities.size(), OSP_FLOAT, opacities.data());
    colorsData.commit();
    opacityData.commit();

    const vec2f valueRange(static_cast<float>(0), static_cast<float>(255));
    transferFcn.set("colors", colorsData);
    transferFcn.set("opacities", opacityData);
    transferFcn.set("valueRange", valueRange);
    transferFcn.commit();

    ospray::cpp::Volume volume("block_bricked_volume");
    volume.set("voxelType", "uchar");
    volume.set("dimensions", vec3i(16));
    volume.set("transferFunction", transferFcn);
    volume.set("gridSpacing", vec3f(0.5f / 16.f));
    const vec3f gridOrigin(myRank / 2.f, 0.f, 0.f);
    volume.set("gridOrigin", gridOrigin);

    std::vector<unsigned char> volumeData(16 * 16 * 16, 0);
    for (size_t i = 0; i < volumeData.size(); ++i) {
      volumeData[i] = i % 256;
    }
    volume.setRegion(volumeData.data(), vec3i(0), vec3i(16));
    volume.commit();

    auto bbox = box3f(gridOrigin, gridOrigin + vec3f(0.5f));
    return std::make_pair(volume, bbox);
  }

  void setupCamera(ospray::cpp::Camera &camera, box3f worldBounds)
  {
    vec3f center = ospcommon::center(worldBounds);
    vec3f diag   = worldBounds.size();
    diag         = max(diag,vec3f(0.3f*length(diag)));
    vec3f from   = center - .75f*vec3f(-.6*diag.x,-1.2f*diag.y,.8f*diag.z);
    vec3f dir    = center - from;

    camera.set("pos", from);
    camera.set("dir", dir);
    camera.set("aspect", static_cast<float>(fbSize.x)/fbSize.y);

    camera.commit();
  }

  void parseCommandLine(int ac, const char **av)
  {
    for (int i = 0; i < ac; ++i) {
      std::string arg = av[i];
      if (arg == "-w") {
        fbSize.x = std::atoi(av[++i]);
      } else if (arg == "-h") {
        fbSize.y = std::atoi(av[++i]);
      } else if (arg == "-spn" || arg == "--spheres-per-node") {
        numSpheresPerNode = std::atoi(av[++i]);
      } else if (arg == "-r" || arg == "--radius") {
        sphereRadius = std::atof(av[++i]);
      } else if (arg == "-nf" || arg == "--num-frames") {
        numFrames = std::atoi(av[++i]);
      } else if (arg == "-l" || arg == "--local") {
        runDistributed = false;
      } else if (arg == "-vol") {
        withVolume = true;
      }
    }
  }

  void initialize_ospray()
  {
    ospray::cpp::Device device;

    if (runDistributed) {
      ospLoadModule("mpi");
      device = ospray::cpp::Device("mpi_distributed");
      device.set("masterRank", 0);
      device.commit();
      device.setCurrent();
    } else {
      device = ospray::cpp::Device();
      device.commit();
      device.setCurrent();
    }

    ospDeviceSetStatusFunc(device.handle(),
                           [](const char *msg) {
                             std::cerr << msg;
                           });
  }

  extern "C" int main(int ac, const char **av)
  {
    parseCommandLine(ac, av);

    initialize_ospray();

    ospray::cpp::Model model;
    auto spheres = makeSpheres();
    model.addGeometry(spheres.first);

    box3f worldBounds = spheres.second;
    if (withVolume) {
      auto volume = makeVolume();
      model.addVolume(volume.first);
      worldBounds.extend(volume.second);
    }

    model.commit();

    DefaultCameraParser cameraClParser;
    cameraClParser.parse(ac, av);
    auto camera = cameraClParser.camera();
    setupCamera(camera, worldBounds);

    ospray::cpp::Renderer renderer("raycast");
    renderer.set("world", model);
    renderer.set("model", model);
    renderer.set("camera", camera);
    renderer.set("bgColor", vec3f(1.f, 1.f, 1.f));
    renderer.commit();

    ospray::cpp::FrameBuffer fb(fbSize,OSP_FB_SRGBA,OSP_FB_COLOR|OSP_FB_ACCUM);
    fb.clear(OSP_FB_ACCUM);

    if (runDistributed) {

      mpicommon::world.barrier();

      auto frameStartTime = ospcommon::getSysTime();

      for (int i = 0; i < numFrames; ++i) {
        if (mpicommon::IamTheMaster())
          std::cout << "rendering frame " << i << std::endl;

        renderer.renderFrame(fb, OSP_FB_COLOR | OSP_FB_ACCUM);
      }

      double seconds = ospcommon::getSysTime() - frameStartTime;

      if (mpicommon::IamTheMaster()) {
        auto *lfb = (uint32_t*)fb.map(OSP_FB_COLOR);
        writePPM("randomSphereTestDistributed.ppm", fbSize.x, fbSize.y, lfb);
        fb.unmap(lfb);
        std::cout << "\noutput: 'randomSphereTestDistributed.ppm'" << std::endl;
        std::cout << "\nrendered " << numFrames << " frames at an avg rate of "
                  << numFrames / seconds << " frames per second" << std::endl;
      }

      mpicommon::world.barrier();

    } else {

      auto frameStartTime = ospcommon::getSysTime();

      for (int i = 0; i < numFrames; ++i) {
        std::cout << "rendering frame " << i << std::endl;

        renderer.renderFrame(fb, OSP_FB_COLOR | OSP_FB_ACCUM);
      }

      double seconds = ospcommon::getSysTime() - frameStartTime;

      auto *lfb = (uint32_t*)fb.map(OSP_FB_COLOR);
      writePPM("randomSphereTestLocal.ppm", fbSize.x, fbSize.y, lfb);
      fb.unmap(lfb);
      std::cout << "\noutput: 'randomSphereTestLocal.ppm'" << std::endl;
      std::cout << "\nrendered " << numFrames << " frames at an avg rate of "
                << numFrames / seconds << " frames per second" << std::endl;

    }

    return 0;
  }

} // ::ospRandSphereTest
<commit_msg>Change TFCN and bgColor a bit<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// 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.                                           //
// ======================================================================== //

// mpiCommon
#include "mpiCommon/MPICommon.h"
// public-ospray
#include "ospray/ospray_cpp/Camera.h"
#include "ospray/ospray_cpp/Data.h"
#include "ospray/ospray_cpp/Device.h"
#include "ospray/ospray_cpp/FrameBuffer.h"
#include "ospray/ospray_cpp/Renderer.h"
#include "ospray/ospray_cpp/TransferFunction.h"
#include "ospray/ospray_cpp/Volume.h"
// ospray apps
#include "common/commandline/CameraParser.h"
#include "widgets/imguiViewer.h"
// stl
#include <random>

#define RUN_LOCAL 0

namespace ospRandSphereTest {

  using namespace ospcommon;

  int   numSpheresPerNode = 100;
  float sphereRadius      = 0.01f;
  float sceneLowerBound   = 0.f;
  float sceneUpperBound   = 1.f;
  vec2i fbSize            = vec2i(1024, 768);
  int   numFrames         = 32;
  bool  runDistributed    = true;
  bool  withVolume        = false;

  //TODO: factor this into a reusable piece inside of ospcommon!!!!!!
  // helper function to write the rendered image as PPM file
  void writePPM(const std::string &fileName,
                const int sizeX, const int sizeY,
                const uint32_t *pixel)
  {
    FILE *file = fopen(fileName.c_str(), "wb");
    fprintf(file, "P6\n%i %i\n255\n", sizeX, sizeY);
    unsigned char *out = (unsigned char *)alloca(3*sizeX);
    for (int y = 0; y < sizeY; y++) {
      auto *in = (const unsigned char *)&pixel[(sizeY-1-y)*sizeX];
      for (int x = 0; x < sizeX; x++) {
        out[3*x + 0] = in[4*x + 0];
        out[3*x + 1] = in[4*x + 1];
        out[3*x + 2] = in[4*x + 2];
      }
      fwrite(out, 3*sizeX, sizeof(char), file);
    }
    fprintf(file, "\n");
    fclose(file);
  }

  std::pair<ospray::cpp::Geometry, box3f> makeSpheres()
  {
    struct Sphere
    {
      vec3f org;
      int colorID {0};
    };

    std::vector<Sphere> spheres(numSpheresPerNode);

    std::mt19937 rng;
    rng.seed(std::random_device()());
    std::uniform_real_distribution<float> dist(sceneLowerBound,
                                               sceneUpperBound);

    for (auto &s : spheres) {
      s.org.x = dist(rng);
      s.org.y = dist(rng);
      s.org.z = dist(rng);
    }

    ospray::cpp::Data sphere_data(numSpheresPerNode * sizeof(Sphere),
                                  OSP_UCHAR, spheres.data());

    auto numRanks = static_cast<float>(mpicommon::numGlobalRanks());
    auto myRank   = mpicommon::globalRank();

#if 1
    float r = (numRanks - myRank) / numRanks;
    float b = myRank / numRanks;
    float g = myRank > numRanks / 2 ? 2 * r : 2 * b;
#else
    float normRank = myRank / numRanks;
    float r = 2 * (1.f - normRank - 0.5f);
    if (r < 0.f) r = 0.f;
    float b = 2 * (normRank - 0.5f);
    if (b < 0.f) b = 0.f;
    float g = myRank < numRanks / 2 ? 1.f - r : 1.f - b;
    g *= 0.5f;
#endif

    vec4f color(r, g, b, 1.f);

    ospray::cpp::Data color_data(1, OSP_FLOAT4, &color);

    ospray::cpp::Geometry geom("spheres");
    geom.set("spheres", sphere_data);
    geom.set("color", color_data);
    geom.set("offset_colorID", int(sizeof(vec3f)));
    geom.set("radius", sphereRadius);
    geom.commit();

    //NOTE: all ranks will have the same bounding box, no matter what spheres
    //      were randomly generated
    auto bbox = box3f(vec3f(sceneLowerBound), vec3f(sceneUpperBound));

    return std::make_pair(geom, bbox);
  }

  std::pair<ospray::cpp::Volume, box3f> makeVolume()
  {
    auto numRanks = static_cast<float>(mpicommon::numGlobalRanks());
    auto myRank   = mpicommon::globalRank();

    ospray::cpp::TransferFunction transferFcn("piecewise_linear");
    const std::vector<vec3f> colors = {
      vec3f(0.231373, 0.298039 , 0.75294),
      vec3f(0.865003, 0.865003 , 0.86500),
      vec3f(0.705882, 0.0156863, 0.14902)
    };
    const std::vector<float> opacities = {0.15, 0.05};
    ospray::cpp::Data colorsData(colors.size(), OSP_FLOAT3, colors.data());
    ospray::cpp::Data opacityData(opacities.size(), OSP_FLOAT, opacities.data());
    colorsData.commit();
    opacityData.commit();

    const vec2f valueRange(static_cast<float>(0), static_cast<float>(255));
    transferFcn.set("colors", colorsData);
    transferFcn.set("opacities", opacityData);
    transferFcn.set("valueRange", valueRange);
    transferFcn.commit();

    ospray::cpp::Volume volume("block_bricked_volume");
    volume.set("voxelType", "uchar");
    volume.set("dimensions", vec3i(16));
    volume.set("transferFunction", transferFcn);
    volume.set("gridSpacing", vec3f(0.5f / 16.f));
    const vec3f gridOrigin(myRank / 2.f, 0.f, 0.f);
    volume.set("gridOrigin", gridOrigin);

    std::vector<unsigned char> volumeData(16 * 16 * 16, 0);
    for (size_t i = 0; i < volumeData.size(); ++i) {
      volumeData[i] = i % 256;
    }
    volume.setRegion(volumeData.data(), vec3i(0), vec3i(16));
    volume.commit();

    auto bbox = box3f(gridOrigin, gridOrigin + vec3f(0.5f));
    return std::make_pair(volume, bbox);
  }

  void setupCamera(ospray::cpp::Camera &camera, box3f worldBounds)
  {
    vec3f center = ospcommon::center(worldBounds);
    vec3f diag   = worldBounds.size();
    diag         = max(diag,vec3f(0.3f*length(diag)));
    vec3f from   = center - .75f*vec3f(-.6*diag.x,-1.2f*diag.y,.8f*diag.z);
    vec3f dir    = center - from;

    camera.set("pos", from);
    camera.set("dir", dir);
    camera.set("aspect", static_cast<float>(fbSize.x)/fbSize.y);

    camera.commit();
  }

  void parseCommandLine(int ac, const char **av)
  {
    for (int i = 0; i < ac; ++i) {
      std::string arg = av[i];
      if (arg == "-w") {
        fbSize.x = std::atoi(av[++i]);
      } else if (arg == "-h") {
        fbSize.y = std::atoi(av[++i]);
      } else if (arg == "-spn" || arg == "--spheres-per-node") {
        numSpheresPerNode = std::atoi(av[++i]);
      } else if (arg == "-r" || arg == "--radius") {
        sphereRadius = std::atof(av[++i]);
      } else if (arg == "-nf" || arg == "--num-frames") {
        numFrames = std::atoi(av[++i]);
      } else if (arg == "-l" || arg == "--local") {
        runDistributed = false;
      } else if (arg == "-vol") {
        withVolume = true;
      }
    }
  }

  void initialize_ospray()
  {
    ospray::cpp::Device device;

    if (runDistributed) {
      ospLoadModule("mpi");
      device = ospray::cpp::Device("mpi_distributed");
      device.set("masterRank", 0);
      device.commit();
      device.setCurrent();
    } else {
      device = ospray::cpp::Device();
      device.commit();
      device.setCurrent();
    }

    ospDeviceSetStatusFunc(device.handle(),
                           [](const char *msg) {
                             std::cerr << msg;
                           });
  }

  extern "C" int main(int ac, const char **av)
  {
    parseCommandLine(ac, av);

    initialize_ospray();

    ospray::cpp::Model model;
    auto spheres = makeSpheres();
    model.addGeometry(spheres.first);

    box3f worldBounds = spheres.second;
    if (withVolume) {
      auto volume = makeVolume();
      model.addVolume(volume.first);
      worldBounds.extend(volume.second);
    }

    model.commit();

    DefaultCameraParser cameraClParser;
    cameraClParser.parse(ac, av);
    auto camera = cameraClParser.camera();
    setupCamera(camera, worldBounds);

    ospray::cpp::Renderer renderer("raycast");
    renderer.set("world", model);
    renderer.set("model", model);
    renderer.set("camera", camera);
    renderer.set("bgColor", vec3f(0.01f, 0.01f, 0.01f));
    renderer.commit();

    ospray::cpp::FrameBuffer fb(fbSize,OSP_FB_SRGBA,OSP_FB_COLOR|OSP_FB_ACCUM);
    fb.clear(OSP_FB_ACCUM);

    if (runDistributed) {

      mpicommon::world.barrier();

      auto frameStartTime = ospcommon::getSysTime();

      for (int i = 0; i < numFrames; ++i) {
        if (mpicommon::IamTheMaster())
          std::cout << "rendering frame " << i << std::endl;

        renderer.renderFrame(fb, OSP_FB_COLOR | OSP_FB_ACCUM);
      }

      double seconds = ospcommon::getSysTime() - frameStartTime;

      if (mpicommon::IamTheMaster()) {
        auto *lfb = (uint32_t*)fb.map(OSP_FB_COLOR);
        writePPM("randomSphereTestDistributed.ppm", fbSize.x, fbSize.y, lfb);
        fb.unmap(lfb);
        std::cout << "\noutput: 'randomSphereTestDistributed.ppm'" << std::endl;
        std::cout << "\nrendered " << numFrames << " frames at an avg rate of "
                  << numFrames / seconds << " frames per second" << std::endl;
      }

      mpicommon::world.barrier();

    } else {

      auto frameStartTime = ospcommon::getSysTime();

      for (int i = 0; i < numFrames; ++i) {
        std::cout << "rendering frame " << i << std::endl;

        renderer.renderFrame(fb, OSP_FB_COLOR | OSP_FB_ACCUM);
      }

      double seconds = ospcommon::getSysTime() - frameStartTime;

      auto *lfb = (uint32_t*)fb.map(OSP_FB_COLOR);
      writePPM("randomSphereTestLocal.ppm", fbSize.x, fbSize.y, lfb);
      fb.unmap(lfb);
      std::cout << "\noutput: 'randomSphereTestLocal.ppm'" << std::endl;
      std::cout << "\nrendered " << numFrames << " frames at an avg rate of "
                << numFrames / seconds << " frames per second" << std::endl;

    }

    return 0;
  }

} // ::ospRandSphereTest
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct JsonWriter
{
	std::ostream &f;
	bool use_selection;

	Design *design;
	Module *module;

	SigMap sigmap;
	int sigidcounter;
	dict<SigBit, string> sigids;

	JsonWriter(std::ostream &f, bool use_selection) : f(f), use_selection(use_selection) { }

	string get_string(string str)
	{
		string newstr = "\"";
		for (char c : str) {
			if (c == '\\')
				newstr += c;
			newstr += c;
		}
		return newstr + "\"";
	}

	string get_name(IdString name)
	{
		return get_string(RTLIL::unescape_id(name));
	}

	string get_bits(SigSpec sig)
	{
		bool first = true;
		string str = "[";
		for (auto bit : sigmap(sig)) {
			str += first ? " " : ", ";
			first = false;
			if (sigids.count(bit) == 0) {
				string &s = sigids[bit];
				if (bit.wire == nullptr) {
					if (bit == State::S0) s = "\"0\"";
					else if (bit == State::S1) s = "\"0\"";
					else if (bit == State::Sz) s = "\"z\"";
					else s = "\"x\"";
				} else
					s = stringf("%d", sigidcounter++);
			}
			str += sigids[bit];
		}
		return str + " ]";
	}

	void write_module(Module *module_)
	{
		module = module_;
		log_assert(module->design == design);
		sigmap.set(module);
		sigids.clear();

		// reserve 0 and 1 to avoid confusion with "0" and "1"
		sigidcounter = 2;

		f << stringf("    %s: {\n", get_name(module->name).c_str());

		f << stringf("      \"ports\": {");
		bool first = true;
		for (auto n : module->ports) {
			Wire *w = module->wire(n);
			if (use_selection && !module->selected(w))
				continue;
			f << stringf("%s\n", first ? "" : ",");
			f << stringf("        %s: {\n", get_name(n).c_str());
			f << stringf("          \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
			f << stringf("          \"bits\": %s\n", get_bits(w).c_str());
			f << stringf("        }");
			first = false;
		}
		f << stringf("\n      },\n");

		f << stringf("      \"cells\": {");
		first = true;
		for (auto c : module->cells()) {
			if (use_selection && !module->selected(c))
				continue;
			f << stringf("%s\n", first ? "" : ",");
			f << stringf("        %s: {\n", get_name(c->name).c_str());
			f << stringf("          \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
			f << stringf("          \"type\": %s,\n", get_name(c->type).c_str());
			f << stringf("          \"parameters\": {");
			bool first2 = true;
			for (auto &param : c->parameters) {
				f << stringf("%s\n", first2 ? "" : ",");
				f << stringf("            %s: ", get_name(param.first).c_str());
				if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
					f << get_string(param.second.decode_string());
				else if (GetSize(param.second.bits) > 32)
					f << get_string(param.second.as_string());
				else
					f << stringf("%d", param.second.as_int());
				first2 = false;
			}
			f << stringf("\n          },\n");
			f << stringf("          \"connections\": {");
			first2 = true;
			for (auto &conn : c->connections()) {
				f << stringf("%s\n", first2 ? "" : ",");
				f << stringf("            %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
				first2 = false;
			}
			f << stringf("\n          }\n");
			f << stringf("        }");
			first = false;
		}
		f << stringf("\n      },\n");

		f << stringf("      \"netnames\": {");
		first = true;
		for (auto w : module->wires()) {
			if (use_selection && !module->selected(w))
				continue;
			f << stringf("%s\n", first ? "" : ",");
			f << stringf("        %s: {\n", get_name(w->name).c_str());
			f << stringf("          \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
			f << stringf("          \"bits\": %s\n", get_bits(w).c_str());
			f << stringf("        }");
			first = false;
		}
		f << stringf("\n      }\n");

		f << stringf("    }");
	}

	void write_design(Design *design_)
	{
		design = design_;
		f << stringf("{\n");
		f << stringf("  \"creator\": %s,\n", get_string(yosys_version_str).c_str());
		f << stringf("  \"modules\": {\n");
		vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
		bool first_module = true;
		for (auto mod : modules) {
			if (!first_module)
				f << stringf(",\n");
			write_module(mod);
			first_module = false;
		}
		f << stringf("\n  }\n");
		f << stringf("}\n");
	}
};

struct JsonBackend : public Backend {
	JsonBackend() : Backend("json", "write design to a JSON file") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    write_json [options] [filename]\n");
		log("\n");
		log("Write a JSON netlist of the current design.\n");
		log("\n");
	}
	virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
	{
		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			// if (args[argidx] == "-verbose") {
			// 	verbose = true;
			// 	continue;
			// }
			break;
		}
		extra_args(f, filename, args, argidx);

		log_header("Executing JSON backend.\n");

		JsonWriter json_writer(*f, false);
		json_writer.write_design(design);
	}
} JsonBackend;

struct JsonPass : public Pass {
	JsonPass() : Pass("json", "write design to a JSON file") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    write_json [options] [selection]\n");
		log("\n");
		log("Write a JSON netlist of all selected objects.\n");
		log("\n");
		log("    -o <filename>\n");
		log("        write to the specified file.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::string filename;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-o" && argidx+1 < args.size()) {
				filename = args[++argidx];
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		std::ostream *f;
		std::stringstream buf;

		if (!filename.empty()) {
			std::ofstream *ff = new std::ofstream;
			ff->open(filename.c_str(), std::ofstream::trunc);
			if (ff->fail()) {
				delete ff;
				log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
			}
			f = ff;
		} else {
			f = &buf;
		}

		JsonWriter json_writer(*f, true);
		json_writer.write_design(design);

		if (!filename.empty()) {
			delete f;
		} else {
			log("%s", buf.str().c_str());
		}
	}
} JsonPass;

PRIVATE_NAMESPACE_END
<commit_msg>Json bugfix<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct JsonWriter
{
	std::ostream &f;
	bool use_selection;

	Design *design;
	Module *module;

	SigMap sigmap;
	int sigidcounter;
	dict<SigBit, string> sigids;

	JsonWriter(std::ostream &f, bool use_selection) : f(f), use_selection(use_selection) { }

	string get_string(string str)
	{
		string newstr = "\"";
		for (char c : str) {
			if (c == '\\')
				newstr += c;
			newstr += c;
		}
		return newstr + "\"";
	}

	string get_name(IdString name)
	{
		return get_string(RTLIL::unescape_id(name));
	}

	string get_bits(SigSpec sig)
	{
		bool first = true;
		string str = "[";
		for (auto bit : sigmap(sig)) {
			str += first ? " " : ", ";
			first = false;
			if (sigids.count(bit) == 0) {
				string &s = sigids[bit];
				if (bit.wire == nullptr) {
					if (bit == State::S0) s = "\"0\"";
					else if (bit == State::S1) s = "\"1\"";
					else if (bit == State::Sz) s = "\"z\"";
					else s = "\"x\"";
				} else
					s = stringf("%d", sigidcounter++);
			}
			str += sigids[bit];
		}
		return str + " ]";
	}

	void write_module(Module *module_)
	{
		module = module_;
		log_assert(module->design == design);
		sigmap.set(module);
		sigids.clear();

		// reserve 0 and 1 to avoid confusion with "0" and "1"
		sigidcounter = 2;

		f << stringf("    %s: {\n", get_name(module->name).c_str());

		f << stringf("      \"ports\": {");
		bool first = true;
		for (auto n : module->ports) {
			Wire *w = module->wire(n);
			if (use_selection && !module->selected(w))
				continue;
			f << stringf("%s\n", first ? "" : ",");
			f << stringf("        %s: {\n", get_name(n).c_str());
			f << stringf("          \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
			f << stringf("          \"bits\": %s\n", get_bits(w).c_str());
			f << stringf("        }");
			first = false;
		}
		f << stringf("\n      },\n");

		f << stringf("      \"cells\": {");
		first = true;
		for (auto c : module->cells()) {
			if (use_selection && !module->selected(c))
				continue;
			f << stringf("%s\n", first ? "" : ",");
			f << stringf("        %s: {\n", get_name(c->name).c_str());
			f << stringf("          \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
			f << stringf("          \"type\": %s,\n", get_name(c->type).c_str());
			f << stringf("          \"parameters\": {");
			bool first2 = true;
			for (auto &param : c->parameters) {
				f << stringf("%s\n", first2 ? "" : ",");
				f << stringf("            %s: ", get_name(param.first).c_str());
				if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
					f << get_string(param.second.decode_string());
				else if (GetSize(param.second.bits) > 32)
					f << get_string(param.second.as_string());
				else
					f << stringf("%d", param.second.as_int());
				first2 = false;
			}
			f << stringf("\n          },\n");
			f << stringf("          \"connections\": {");
			first2 = true;
			for (auto &conn : c->connections()) {
				f << stringf("%s\n", first2 ? "" : ",");
				f << stringf("            %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
				first2 = false;
			}
			f << stringf("\n          }\n");
			f << stringf("        }");
			first = false;
		}
		f << stringf("\n      },\n");

		f << stringf("      \"netnames\": {");
		first = true;
		for (auto w : module->wires()) {
			if (use_selection && !module->selected(w))
				continue;
			f << stringf("%s\n", first ? "" : ",");
			f << stringf("        %s: {\n", get_name(w->name).c_str());
			f << stringf("          \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
			f << stringf("          \"bits\": %s\n", get_bits(w).c_str());
			f << stringf("        }");
			first = false;
		}
		f << stringf("\n      }\n");

		f << stringf("    }");
	}

	void write_design(Design *design_)
	{
		design = design_;
		f << stringf("{\n");
		f << stringf("  \"creator\": %s,\n", get_string(yosys_version_str).c_str());
		f << stringf("  \"modules\": {\n");
		vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
		bool first_module = true;
		for (auto mod : modules) {
			if (!first_module)
				f << stringf(",\n");
			write_module(mod);
			first_module = false;
		}
		f << stringf("\n  }\n");
		f << stringf("}\n");
	}
};

struct JsonBackend : public Backend {
	JsonBackend() : Backend("json", "write design to a JSON file") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    write_json [options] [filename]\n");
		log("\n");
		log("Write a JSON netlist of the current design.\n");
		log("\n");
	}
	virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
	{
		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			// if (args[argidx] == "-verbose") {
			// 	verbose = true;
			// 	continue;
			// }
			break;
		}
		extra_args(f, filename, args, argidx);

		log_header("Executing JSON backend.\n");

		JsonWriter json_writer(*f, false);
		json_writer.write_design(design);
	}
} JsonBackend;

struct JsonPass : public Pass {
	JsonPass() : Pass("json", "write design to a JSON file") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    write_json [options] [selection]\n");
		log("\n");
		log("Write a JSON netlist of all selected objects.\n");
		log("\n");
		log("    -o <filename>\n");
		log("        write to the specified file.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::string filename;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-o" && argidx+1 < args.size()) {
				filename = args[++argidx];
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		std::ostream *f;
		std::stringstream buf;

		if (!filename.empty()) {
			std::ofstream *ff = new std::ofstream;
			ff->open(filename.c_str(), std::ofstream::trunc);
			if (ff->fail()) {
				delete ff;
				log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
			}
			f = ff;
		} else {
			f = &buf;
		}

		JsonWriter json_writer(*f, true);
		json_writer.write_design(design);

		if (!filename.empty()) {
			delete f;
		} else {
			log("%s", buf.str().c_str());
		}
	}
} JsonPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>
#include <gst-helper/gstcaps_dutils_interop.h>

#include <dutils_img_lib/dutils_gst_interop.h>
#include <gst-helper/gst_gvalue_helper.h>

#include <map>
#include <limits>

std::optional<img::dim> gst_helper::get_gst_struct_image_dim(const GstStructure& structure)
{
    int width = 0;
    int height = 0;
    if (!gst_structure_get_int(&structure, "width", &width)
        || !gst_structure_get_int(&structure, "height", &height))
    {
        return {};
    }
    return img::dim { width, height };
}

img::fourcc gst_helper::get_gst_struct_fcc(const GstStructure& structure)
{
    const auto type = gst_structure_get_field_type(&structure, "format");

    assert(gst_structure_get_name(&structure) != nullptr);

    const char* format = nullptr;
    if (type == G_TYPE_STRING)
    {
        format = gst_structure_get_string(&structure, "format");
    }
    else if (type == GST_TYPE_LIST)
    {
        return img::fourcc::FCC_NULL;
    }
    else
    {
        return img::fourcc::FCC_NULL;
    }
    return img_lib::gst::gst_caps_string_to_fourcc(gst_structure_get_name(&structure),
                                                   format == nullptr ? "" : format);
}

img::img_type gst_helper::get_gst_struct_image_type(const GstStructure& structure)
{
    auto dim_opt = get_gst_struct_image_dim(structure);
    if (!dim_opt)
    {
        return {};
    }
    img::fourcc fcc = get_gst_struct_fcc(structure);
    if (fcc == img::fourcc::FCC_NULL)
    {
        return {};
    }
    return img::make_img_type(fcc, dim_opt.value());
}

auto gst_helper::get_img_type_from_fixated_gstcaps( const GstCaps& caps ) -> img::img_type
{
    auto struc = gst_caps_get_structure( &caps, 0 );
    if( struc == nullptr ) {
        return {};
    }
    return get_gst_struct_image_type( *struc );
}

std::optional<double> gst_helper::get_gst_struct_framerate(const GstStructure& structure)
{
    const GValue* frame_rate_field = gst_structure_get_value(&structure, "framerate");

    if (frame_rate_field == nullptr)
    {
        return {};
    }

    int fps_numerator = gst_value_get_fraction_numerator(frame_rate_field);
    int fps_denominator = gst_value_get_fraction_denominator(frame_rate_field);
    return (double)fps_numerator / (double)fps_denominator;
}

void gst_helper::set_gst_struct_framerate(GstStructure& structure, double framerate) noexcept
{
    GValue value = G_VALUE_INIT;
    g_value_init(&value, GST_TYPE_FRACTION);

    int fps_min_num = 0;
    int fps_min_den = 0;
    gst_util_double_to_fraction(framerate, &fps_min_num, &fps_min_den);
    gst_value_set_fraction(&value, fps_min_num, fps_min_den);
    gst_structure_take_value(&structure, "framerate", &value);
}

gst_helper::gst_ptr<GstCaps>    gst_helper::generate_caps_with_dim( const std::vector<img::fourcc>& fcc_list )
{
    GstCaps* caps = gst_caps_new_empty();

    std::map<std::string, std::vector<const char*>> simple_map;

    for( const auto fcc : fcc_list )
    {
        auto [prefix, format] = img_lib::gst::fourcc_to_gst_caps_descr( fcc );
        if( !prefix )
        {
            //GST_WARN( "Format has empty caps string. Ignoring %s", img::fcc_to_string( fcc ).c_str() );
            continue;
        }

        simple_map[prefix].push_back( format );
    }

    for( auto&& [struct_type, format_string_list] : simple_map )
    {
        GValue format_list = {};
        g_value_init( &format_list, GST_TYPE_LIST );
        for( auto&& format : format_string_list )
        {
            GValue tmp = {};
            g_value_init( &tmp, G_TYPE_STRING );
            g_value_set_string( &tmp, format );
            gst_value_list_append_and_take_value( &format_list, &tmp );
        }

        GstStructure* structure = gst_structure_new_empty( struct_type.c_str() );
        gst_structure_take_value( structure, "format", &format_list );

        GValue gvalue_width = G_VALUE_INIT;
        g_value_init( &gvalue_width, GST_TYPE_INT_RANGE );
        gst_value_set_int_range_step( &gvalue_width, 1, std::numeric_limits<gint>::max(), 1 );

        GValue gvalue_height = G_VALUE_INIT;
        g_value_init( &gvalue_height, GST_TYPE_INT_RANGE );
        gst_value_set_int_range_step( &gvalue_height, 1, std::numeric_limits<gint>::max(), 1 );

        gst_structure_take_value( structure, "width", &gvalue_width );
        gst_structure_take_value( structure, "height", &gvalue_height );
        //gst_structure_take_value( structure, "framerate", &gvalue_fps_range );  // takes ownership of gvalue_fps_range

        gst_caps_append_structure( caps, structure );
    }

    return gst_helper::make_wrap_ptr( caps );
}

auto gst_helper::convert_GstStructure_to_fcc_list( const GstStructure& strct ) -> std::vector<img::fourcc>
{
    auto struct_name_ = gst_structure_get_name( &strct );
    assert( struct_name_ != nullptr );
    if( struct_name_ == nullptr ) {
        GST_ERROR( "GstStructure with no name" );
        return {};
    }
    std::string_view format_type = struct_name_;

    auto gval = gst_structure_get_value( &strct, "format" );
    if( gval == nullptr ) {
        return {};
    }

    std::vector<img::fourcc> rval;
    auto add_fcc = [&rval,format_type]( const char* str ) {
        if( str != nullptr ) {
            auto fcc = img_lib::gst::gst_caps_string_to_fourcc( format_type, str );
            if( fcc != img::fourcc::FCC_NULL ) {
                rval.push_back( fcc );
            }
        }
    };

    if( G_VALUE_TYPE( gval ) == G_TYPE_STRING )
    {
        add_fcc( g_value_get_string( gval ) );
    }
    else if( G_VALUE_TYPE( gval ) == GST_TYPE_LIST || G_VALUE_TYPE( gval ) == GST_TYPE_ARRAY )
    {
        for( auto&& entry : gst_helper::gst_list_or_array_to_GValue_vector( *gval ) )
        {
            add_fcc( g_value_get_string( entry ) );
        }
    }
    else
    {
        return {};
    }
    return rval;
}

auto gst_helper::convert_GstCaps_to_fcc_list( const GstCaps& caps ) ->std::vector<img::fourcc>
{
    int struct_cnt = gst_caps_get_size( &caps );

    std::vector<img::fourcc> rval;
    for( int i = 0; i < struct_cnt; ++i ) {
        GstStructure* entry = gst_caps_get_structure( &caps, i );
        assert( entry != nullptr );
        if( entry == nullptr ) {
            return {};
        }
        auto vec = convert_GstStructure_to_fcc_list( *entry );
        rval.insert( rval.end(), vec.begin(), vec.end() );
    }
    return rval;
}
<commit_msg>gst-helper: Change convert_GstStructure_to_fcc_list to only return unique fcc items<commit_after>
#include <gst-helper/gstcaps_dutils_interop.h>

#include <dutils_img_lib/dutils_gst_interop.h>
#include <gst-helper/gst_gvalue_helper.h>

#include <map>
#include <limits>
#include <algorithm>

std::optional<img::dim> gst_helper::get_gst_struct_image_dim(const GstStructure& structure)
{
    int width = 0;
    int height = 0;
    if (!gst_structure_get_int(&structure, "width", &width)
        || !gst_structure_get_int(&structure, "height", &height))
    {
        return {};
    }
    return img::dim { width, height };
}

img::fourcc gst_helper::get_gst_struct_fcc(const GstStructure& structure)
{
    const auto type = gst_structure_get_field_type(&structure, "format");

    assert(gst_structure_get_name(&structure) != nullptr);

    const char* format = nullptr;
    if (type == G_TYPE_STRING)
    {
        format = gst_structure_get_string(&structure, "format");
    }
    else if (type == GST_TYPE_LIST)
    {
        return img::fourcc::FCC_NULL;
    }
    else
    {
        return img::fourcc::FCC_NULL;
    }
    return img_lib::gst::gst_caps_string_to_fourcc(gst_structure_get_name(&structure),
                                                   format == nullptr ? "" : format);
}

img::img_type gst_helper::get_gst_struct_image_type(const GstStructure& structure)
{
    auto dim_opt = get_gst_struct_image_dim(structure);
    if (!dim_opt)
    {
        return {};
    }
    img::fourcc fcc = get_gst_struct_fcc(structure);
    if (fcc == img::fourcc::FCC_NULL)
    {
        return {};
    }
    return img::make_img_type(fcc, dim_opt.value());
}

auto gst_helper::get_img_type_from_fixated_gstcaps( const GstCaps& caps ) -> img::img_type
{
    auto struc = gst_caps_get_structure( &caps, 0 );
    if( struc == nullptr ) {
        return {};
    }
    return get_gst_struct_image_type( *struc );
}

std::optional<double> gst_helper::get_gst_struct_framerate(const GstStructure& structure)
{
    const GValue* frame_rate_field = gst_structure_get_value(&structure, "framerate");

    if (frame_rate_field == nullptr)
    {
        return {};
    }

    int fps_numerator = gst_value_get_fraction_numerator(frame_rate_field);
    int fps_denominator = gst_value_get_fraction_denominator(frame_rate_field);
    return (double)fps_numerator / (double)fps_denominator;
}

void gst_helper::set_gst_struct_framerate(GstStructure& structure, double framerate) noexcept
{
    GValue value = G_VALUE_INIT;
    g_value_init(&value, GST_TYPE_FRACTION);

    int fps_min_num = 0;
    int fps_min_den = 0;
    gst_util_double_to_fraction(framerate, &fps_min_num, &fps_min_den);
    gst_value_set_fraction(&value, fps_min_num, fps_min_den);
    gst_structure_take_value(&structure, "framerate", &value);
}

gst_helper::gst_ptr<GstCaps>    gst_helper::generate_caps_with_dim( const std::vector<img::fourcc>& fcc_list )
{
    GstCaps* caps = gst_caps_new_empty();

    std::map<std::string, std::vector<const char*>> simple_map;

    for( const auto fcc : fcc_list )
    {
        auto [prefix, format] = img_lib::gst::fourcc_to_gst_caps_descr( fcc );
        if( !prefix )
        {
            //GST_WARN( "Format has empty caps string. Ignoring %s", img::fcc_to_string( fcc ).c_str() );
            continue;
        }

        simple_map[prefix].push_back( format );
    }

    for( auto&& [struct_type, format_string_list] : simple_map )
    {
        GValue format_list = {};
        g_value_init( &format_list, GST_TYPE_LIST );
        for( auto&& format : format_string_list )
        {
            GValue tmp = {};
            g_value_init( &tmp, G_TYPE_STRING );
            g_value_set_string( &tmp, format );
            gst_value_list_append_and_take_value( &format_list, &tmp );
        }

        GstStructure* structure = gst_structure_new_empty( struct_type.c_str() );
        gst_structure_take_value( structure, "format", &format_list );

        GValue gvalue_width = G_VALUE_INIT;
        g_value_init( &gvalue_width, GST_TYPE_INT_RANGE );
        gst_value_set_int_range_step( &gvalue_width, 1, std::numeric_limits<gint>::max(), 1 );

        GValue gvalue_height = G_VALUE_INIT;
        g_value_init( &gvalue_height, GST_TYPE_INT_RANGE );
        gst_value_set_int_range_step( &gvalue_height, 1, std::numeric_limits<gint>::max(), 1 );

        gst_structure_take_value( structure, "width", &gvalue_width );
        gst_structure_take_value( structure, "height", &gvalue_height );
        //gst_structure_take_value( structure, "framerate", &gvalue_fps_range );  // takes ownership of gvalue_fps_range

        gst_caps_append_structure( caps, structure );
    }

    return gst_helper::make_wrap_ptr( caps );
}

auto gst_helper::convert_GstStructure_to_fcc_list( const GstStructure& strct ) -> std::vector<img::fourcc>
{
    auto struct_name_ = gst_structure_get_name( &strct );
    assert( struct_name_ != nullptr );
    if( struct_name_ == nullptr ) {
        GST_ERROR( "GstStructure with no name" );
        return {};
    }
    std::string_view format_type = struct_name_;

    auto gval = gst_structure_get_value( &strct, "format" );
    if( gval == nullptr ) {
        return {};
    }

    std::vector<img::fourcc> rval;
    auto add_fcc = [&rval,format_type]( const char* str ) {
        if( str != nullptr ) {
            auto fcc = img_lib::gst::gst_caps_string_to_fourcc( format_type, str );
            if( fcc != img::fourcc::FCC_NULL ) {
                rval.push_back( fcc );
            }
        }
    };

    if( G_VALUE_TYPE( gval ) == G_TYPE_STRING )
    {
        add_fcc( g_value_get_string( gval ) );
    }
    else if( G_VALUE_TYPE( gval ) == GST_TYPE_LIST || G_VALUE_TYPE( gval ) == GST_TYPE_ARRAY )
    {
        for( auto&& entry : gst_helper::gst_list_or_array_to_GValue_vector( *gval ) )
        {
            add_fcc( g_value_get_string( entry ) );
        }
    }
    else
    {
        return {};
    }
    return rval;
}

auto gst_helper::convert_GstCaps_to_fcc_list( const GstCaps& caps ) ->std::vector<img::fourcc>
{
    int struct_cnt = gst_caps_get_size( &caps );

    std::vector<img::fourcc> rval;
    for( int i = 0; i < struct_cnt; ++i ) {
        GstStructure* entry = gst_caps_get_structure( &caps, i );
        assert( entry != nullptr );
        if( entry == nullptr ) {
            return {};
        }
        for( auto&& new_fcc : convert_GstStructure_to_fcc_list( *entry ) )
        {
            const bool already_present = std::any_of( rval.begin(), rval.end(), [new_fcc]( auto fcc_in_rval ) { return fcc_in_rval == new_fcc; } );
            if( !already_present )
            {
                rval.push_back( new_fcc );
            }
        }
    }

    return rval;
}
<|endoftext|>


<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/render/detail/texture_extraction_detail.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef TEXTURE_EXTRACTION_DETAIL_HPP_
#define TEXTURE_EXTRACTION_DETAIL_HPP_

#include "eos/core/Image.hpp"
#include "eos/render/Rect.hpp"
#include "eos/render/detail/render_detail.hpp"

#include "glm/vec2.hpp"
#include "glm/vec4.hpp"

#include "Eigen/Core"

#include "opencv2/core/core.hpp"

/**
 * Implementations of internal functions, not part of the
 * API we expose and not meant to be used by a user.
 */
namespace eos {
	namespace render {
		namespace detail {

/**
 * Computes whether the given point is inside (or on the border of) the triangle
 * formed out of the given three vertices.
 *
 * @param[in] point The point to check.
 * @param[in] triV0 First vertex.
 * @param[in] triV1 Second vertex.
 * @param[in] triV2 Third vertex.
 * @return Whether the point is inside the triangle.
 */
inline bool is_point_in_triangle(cv::Point2f point, cv::Point2f triV0, cv::Point2f triV1, cv::Point2f triV2) {
	// See http://www.blackpawn.com/texts/pointinpoly/
	// Compute vectors
	cv::Point2f v0 = triV2 - triV0;
	cv::Point2f v1 = triV1 - triV0;
	cv::Point2f v2 = point - triV0;

	// Compute dot products
	float dot00 = v0.dot(v0);
	float dot01 = v0.dot(v1);
	float dot02 = v0.dot(v2);
	float dot11 = v1.dot(v1);
	float dot12 = v1.dot(v2);

	// Compute barycentric coordinates
	float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
	float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
	float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

	// Check if point is in triangle
	return (u >= 0) && (v >= 0) && (u + v < 1);
};

/**
 * Computes whether the given point is inside (or on the border of) the triangle
 * formed out of the given three vertices.
 *
 * @param[in] point The point to check.
 * @param[in] triV0 First vertex.
 * @param[in] triV1 Second vertex.
 * @param[in] triV2 Third vertex.
 * @return Whether the point is inside the triangle.
 */
inline bool is_point_in_triangle(Eigen::Vector2f point, Eigen::Vector2f triV0, Eigen::Vector2f triV1, Eigen::Vector2f triV2) {
	// See http://www.blackpawn.com/texts/pointinpoly/
	// Compute vectors
	Eigen::Vector2f v0 = triV2 - triV0;
	Eigen::Vector2f v1 = triV1 - triV0;
	Eigen::Vector2f v2 = point - triV0;

	// Compute dot products
	float dot00 = v0.dot(v0);
	float dot01 = v0.dot(v1);
	float dot02 = v0.dot(v2);
	float dot11 = v1.dot(v1);
	float dot12 = v1.dot(v2);

	// Compute barycentric coordinates
	float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
	float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
	float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

	// Check if point is in triangle
	return (u >= 0) && (v >= 0) && (u + v < 1);
};

/**
 * Checks whether all pixels in the given triangle are visible and
 * returns true if and only if the whole triangle is visible.
 * The vertices should be given in screen coordinates, but with their
 * z-values preserved, so they can be compared against the depthbuffer.
 *
 * Obviously the depthbuffer given should have been created with the same projection
 * matrix than the texture extraction is called with.
 *
 * Also, we don't do perspective-correct interpolation here I think, so only
 * use it with affine and orthographic projection matrices.
 *
 * @param[in] v0 First vertex, in screen coordinates (but still with their z-value).
 * @param[in] v1 Second vertex.
 * @param[in] v2 Third vertex.
 * @param[in] depthbuffer Pre-calculated depthbuffer.
 * @return True if the whole triangle is visible in the image.
 */
inline bool is_triangle_visible(const glm::tvec4<float>& v0, const glm::tvec4<float>& v1, const glm::tvec4<float>& v2, const core::Image1d& depthbuffer)
{
	// #Todo: Actually, only check the 3 vertex points, don't loop over the pixels - this should be enough.

	auto viewport_width = depthbuffer.cols;
	auto viewport_height = depthbuffer.rows;

	// Well, in in principle, we'd have to do the whole stuff as in render(), like
	// clipping against the frustums etc.
	// But as long as our model is fully on the screen, we're fine. Todo: Doublecheck that.

	if (!detail::are_vertices_ccw_in_screen_space(glm::tvec2<float>(v0), glm::tvec2<float>(v1), glm::tvec2<float>(v2)))
		return false;

	Rect<int> bbox = detail::calculate_clipped_bounding_box(glm::tvec2<float>(v0), glm::tvec2<float>(v1), glm::tvec2<float>(v2), viewport_width, viewport_height);
	int minX = bbox.x;
	int maxX = bbox.x + bbox.width;
	int minY = bbox.y;
	int maxY = bbox.y + bbox.height;

	//if (t.maxX <= t.minX || t.maxY <= t.minY) 	// Note: Can the width/height of the bbox be negative? Maybe we only need to check for equality here?
	//	continue;									// Also, I'm not entirely sure why I commented this out

	bool whole_triangle_is_visible = true;
	for (int yi = minY; yi <= maxY; yi++)
	{
		for (int xi = minX; xi <= maxX; xi++)
		{
			// we want centers of pixels to be used in computations. Do we?
			const float x = static_cast<float>(xi) + 0.5f;
			const float y = static_cast<float>(yi) + 0.5f;
			// these will be used for barycentric weights computation
			const double one_over_v0ToLine12 = 1.0 / detail::implicit_line(v0[0], v0[1], v1, v2);
			const double one_over_v1ToLine20 = 1.0 / detail::implicit_line(v1[0], v1[1], v2, v0);
			const double one_over_v2ToLine01 = 1.0 / detail::implicit_line(v2[0], v2[1], v0, v1);
			// affine barycentric weights
			const double alpha = detail::implicit_line(x, y, v1, v2) * one_over_v0ToLine12;
			const double beta = detail::implicit_line(x, y, v2, v0) * one_over_v1ToLine20;
			const double gamma = detail::implicit_line(x, y, v0, v1) * one_over_v2ToLine01;

			// if pixel (x, y) is inside the triangle or on one of its edges
			if (alpha >= 0 && beta >= 0 && gamma >= 0)
			{
				const double z_affine = alpha*static_cast<double>(v0[2]) + beta*static_cast<double>(v1[2]) + gamma*static_cast<double>(v2[2]);
				if (z_affine < depthbuffer(yi, xi)) {
					whole_triangle_is_visible = false;
					break;
				}
			}
		}
		if (!whole_triangle_is_visible) {
			break;
		}
	}

	if (!whole_triangle_is_visible) {
		return false;
	}
	return true;
};

		} /* namespace detail */
	} /* namespace render */
} /* namespace eos */

#endif /* TEXTURE_EXTRACTION_DETAIL_HPP_ */
<commit_msg>Removed is_point_in_triangle overload with cv::Point2f<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/render/detail/texture_extraction_detail.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef TEXTURE_EXTRACTION_DETAIL_HPP_
#define TEXTURE_EXTRACTION_DETAIL_HPP_

#include "eos/core/Image.hpp"
#include "eos/render/Rect.hpp"
#include "eos/render/detail/render_detail.hpp"

#include "glm/vec2.hpp"
#include "glm/vec4.hpp"

#include "Eigen/Core"

#include "opencv2/core/core.hpp"

/**
 * Implementations of internal functions, not part of the
 * API we expose and not meant to be used by a user.
 */
namespace eos {
	namespace render {
		namespace detail {

/**
 * Computes whether the given point is inside (or on the border of) the triangle
 * formed out of the given three vertices.
 *
 * @param[in] point The point to check.
 * @param[in] triV0 First vertex.
 * @param[in] triV1 Second vertex.
 * @param[in] triV2 Third vertex.
 * @return Whether the point is inside the triangle.
 */
inline bool is_point_in_triangle(Eigen::Vector2f point, Eigen::Vector2f triV0, Eigen::Vector2f triV1, Eigen::Vector2f triV2) {
	// See http://www.blackpawn.com/texts/pointinpoly/
	// Compute vectors
	Eigen::Vector2f v0 = triV2 - triV0;
	Eigen::Vector2f v1 = triV1 - triV0;
	Eigen::Vector2f v2 = point - triV0;

	// Compute dot products
	float dot00 = v0.dot(v0);
	float dot01 = v0.dot(v1);
	float dot02 = v0.dot(v2);
	float dot11 = v1.dot(v1);
	float dot12 = v1.dot(v2);

	// Compute barycentric coordinates
	float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
	float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
	float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

	// Check if point is in triangle
	return (u >= 0) && (v >= 0) && (u + v < 1);
};

/**
 * Checks whether all pixels in the given triangle are visible and
 * returns true if and only if the whole triangle is visible.
 * The vertices should be given in screen coordinates, but with their
 * z-values preserved, so they can be compared against the depthbuffer.
 *
 * Obviously the depthbuffer given should have been created with the same projection
 * matrix than the texture extraction is called with.
 *
 * Also, we don't do perspective-correct interpolation here I think, so only
 * use it with affine and orthographic projection matrices.
 *
 * @param[in] v0 First vertex, in screen coordinates (but still with their z-value).
 * @param[in] v1 Second vertex.
 * @param[in] v2 Third vertex.
 * @param[in] depthbuffer Pre-calculated depthbuffer.
 * @return True if the whole triangle is visible in the image.
 */
inline bool is_triangle_visible(const glm::tvec4<float>& v0, const glm::tvec4<float>& v1, const glm::tvec4<float>& v2, const core::Image1d& depthbuffer)
{
	// #Todo: Actually, only check the 3 vertex points, don't loop over the pixels - this should be enough.

	auto viewport_width = depthbuffer.cols;
	auto viewport_height = depthbuffer.rows;

	// Well, in in principle, we'd have to do the whole stuff as in render(), like
	// clipping against the frustums etc.
	// But as long as our model is fully on the screen, we're fine. Todo: Doublecheck that.

	if (!detail::are_vertices_ccw_in_screen_space(glm::tvec2<float>(v0), glm::tvec2<float>(v1), glm::tvec2<float>(v2)))
		return false;

	Rect<int> bbox = detail::calculate_clipped_bounding_box(glm::tvec2<float>(v0), glm::tvec2<float>(v1), glm::tvec2<float>(v2), viewport_width, viewport_height);
	int minX = bbox.x;
	int maxX = bbox.x + bbox.width;
	int minY = bbox.y;
	int maxY = bbox.y + bbox.height;

	//if (t.maxX <= t.minX || t.maxY <= t.minY) 	// Note: Can the width/height of the bbox be negative? Maybe we only need to check for equality here?
	//	continue;									// Also, I'm not entirely sure why I commented this out

	bool whole_triangle_is_visible = true;
	for (int yi = minY; yi <= maxY; yi++)
	{
		for (int xi = minX; xi <= maxX; xi++)
		{
			// we want centers of pixels to be used in computations. Do we?
			const float x = static_cast<float>(xi) + 0.5f;
			const float y = static_cast<float>(yi) + 0.5f;
			// these will be used for barycentric weights computation
			const double one_over_v0ToLine12 = 1.0 / detail::implicit_line(v0[0], v0[1], v1, v2);
			const double one_over_v1ToLine20 = 1.0 / detail::implicit_line(v1[0], v1[1], v2, v0);
			const double one_over_v2ToLine01 = 1.0 / detail::implicit_line(v2[0], v2[1], v0, v1);
			// affine barycentric weights
			const double alpha = detail::implicit_line(x, y, v1, v2) * one_over_v0ToLine12;
			const double beta = detail::implicit_line(x, y, v2, v0) * one_over_v1ToLine20;
			const double gamma = detail::implicit_line(x, y, v0, v1) * one_over_v2ToLine01;

			// if pixel (x, y) is inside the triangle or on one of its edges
			if (alpha >= 0 && beta >= 0 && gamma >= 0)
			{
				const double z_affine = alpha*static_cast<double>(v0[2]) + beta*static_cast<double>(v1[2]) + gamma*static_cast<double>(v2[2]);
				if (z_affine < depthbuffer(yi, xi)) {
					whole_triangle_is_visible = false;
					break;
				}
			}
		}
		if (!whole_triangle_is_visible) {
			break;
		}
	}

	if (!whole_triangle_is_visible) {
		return false;
	}
	return true;
};

		} /* namespace detail */
	} /* namespace render */
} /* namespace eos */

#endif /* TEXTURE_EXTRACTION_DETAIL_HPP_ */
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#ifndef UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED
#define UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED

#include <uavcan/debug.hpp>
#include <uavcan/util/method_binder.hpp>
#include <uavcan/node/subscriber.hpp>
#include <uavcan/node/timer.hpp>
#include <uavcan/protocol/NodeStatus.hpp>
#include <cassert>
#include <cstdlib>

namespace uavcan
{
/**
 * This class implements the core functionality of a network monitor.
 * It can be extended by inheritance to add more complex logic, or used directly as is.
 */
class UAVCAN_EXPORT NodeStatusMonitor
{
public:
    struct NodeStatus
    {
        uint8_t health   : 2;
        uint8_t mode     : 3;
        uint8_t sub_mode : 3;

        NodeStatus() :
            health(protocol::NodeStatus::HEALTH_CRITICAL),
            mode(protocol::NodeStatus::MODE_OFFLINE),
            sub_mode(0)
        {
            StaticAssert<protocol::NodeStatus::FieldTypes::health::BitLen   == 2>::check();
            StaticAssert<protocol::NodeStatus::FieldTypes::mode::BitLen     == 3>::check();
            StaticAssert<protocol::NodeStatus::FieldTypes::sub_mode::BitLen == 3>::check();
        }

        bool operator!=(const NodeStatus rhs) const { return !operator==(rhs); }
        bool operator==(const NodeStatus rhs) const
        {
            return std::memcmp(this, &rhs, sizeof(NodeStatus)) == 0;
        }

#if UAVCAN_TOSTRING
        std::string toString() const
        {
            char buf[40];
            (void)snprintf(buf, sizeof(buf), "health=%d mode=%d sub_mode=%d", int(health), int(mode), int(sub_mode));
            return std::string(buf);
        }
#endif
    };

    struct NodeStatusChangeEvent
    {
        NodeID node_id;
        NodeStatus status;
        NodeStatus old_status;
        bool was_known;

        NodeStatusChangeEvent() :
            was_known(false)
        { }
    };

private:
    enum { TimerPeriodMs100 = 4 };

    typedef MethodBinder<NodeStatusMonitor*,
                         void (NodeStatusMonitor::*)(const ReceivedDataStructure<protocol::NodeStatus>&)>
            NodeStatusCallback;

    typedef MethodBinder<NodeStatusMonitor*, void (NodeStatusMonitor::*)(const TimerEvent&)> TimerCallback;

    Subscriber<protocol::NodeStatus, NodeStatusCallback, MaxNetworkSizeHint, 0> sub_;

    TimerEventForwarder<TimerCallback> timer_;

    struct Entry
    {
        NodeStatus status;
        int8_t time_since_last_update_ms100;
        Entry() :
            time_since_last_update_ms100(-1)
        { }
    };

    mutable Entry entries_[NodeID::Max];  // [1, NodeID::Max]

    Entry& getEntry(NodeID node_id) const
    {
        if (node_id.get() < 1 || node_id.get() > NodeID::Max)
        {
            handleFatalError("NodeStatusMonitor NodeID");
        }
        return entries_[node_id.get() - 1];
    }

    void changeNodeStatus(const NodeID node_id, const Entry new_entry_value)
    {
        Entry& entry = getEntry(node_id);
        if (entry.status != new_entry_value.status)
        {
            NodeStatusChangeEvent event;
            event.node_id    = node_id;
            event.old_status = entry.status;
            event.status     = new_entry_value.status;
            event.was_known  = entry.time_since_last_update_ms100 >= 0;

            UAVCAN_TRACE("NodeStatusMonitor", "Node %i [%s] status change: [%s] --> [%s]", int(node_id.get()),
                         (event.was_known ? "known" : "new"),
                         event.old_status.toString().c_str(), event.status.toString().c_str());

            handleNodeStatusChange(event);
        }
        entry = new_entry_value;
    }

    void handleNodeStatus(const ReceivedDataStructure<protocol::NodeStatus>& msg)
    {
        Entry new_entry;
        new_entry.time_since_last_update_ms100 = 0;
        new_entry.status.health   = msg.health   & ((1 << protocol::NodeStatus::FieldTypes::health::BitLen) - 1);
        new_entry.status.mode     = msg.mode     & ((1 << protocol::NodeStatus::FieldTypes::mode::BitLen) - 1);
        new_entry.status.sub_mode = msg.sub_mode & ((1 << protocol::NodeStatus::FieldTypes::sub_mode::BitLen) - 1);

        changeNodeStatus(msg.getSrcNodeID(), new_entry);

        handleNodeStatusMessage(msg);
    }

    void handleTimerEvent(const TimerEvent&)
    {
        const int OfflineTimeoutMs100 = protocol::NodeStatus::OFFLINE_TIMEOUT_MS / 100;

        for (uint8_t i = 1; i <= NodeID::Max; i++)
        {
            const NodeID nid(i);
            UAVCAN_ASSERT(nid.isUnicast());

            Entry& entry = getEntry(nid);
            if (entry.time_since_last_update_ms100 >= 0 &&
                entry.status.mode != protocol::NodeStatus::MODE_OFFLINE)
            {
                entry.time_since_last_update_ms100 =
                    int8_t(entry.time_since_last_update_ms100 + int8_t(TimerPeriodMs100));

                if (entry.time_since_last_update_ms100 >= OfflineTimeoutMs100)
                {
                    Entry new_entry_value = entry;
                    new_entry_value.time_since_last_update_ms100 = OfflineTimeoutMs100;
                    new_entry_value.status.mode = protocol::NodeStatus::MODE_OFFLINE;
                    changeNodeStatus(nid, new_entry_value);
                }
            }
        }
    }

protected:
    /**
     * Called when a node becomes online, changes status or goes offline.
     * Refer to uavcan.protocol.NodeStatus for the offline timeout value.
     * Overriding is not required.
     */
    virtual void handleNodeStatusChange(const NodeStatusChangeEvent& event)
    {
        (void)event;
    }

    /**
     * Called for every received message uavcan.protocol.NodeStatus after handleNodeStatusChange(), even
     * if the status code did not change.
     * Overriding is not required.
     */
    virtual void handleNodeStatusMessage(const ReceivedDataStructure<protocol::NodeStatus>& msg)
    {
        (void)msg;
    }

public:
    explicit NodeStatusMonitor(INode& node)
        : sub_(node)
        , timer_(node)
    { }

    virtual ~NodeStatusMonitor() { }

    /**
     * Starts the monitor.
     * Destroy the object to stop it.
     * Returns negative error code.
     */
    int start()
    {
        const int res = sub_.start(NodeStatusCallback(this, &NodeStatusMonitor::handleNodeStatus));
        if (res >= 0)
        {
            timer_.setCallback(TimerCallback(this, &NodeStatusMonitor::handleTimerEvent));
            timer_.startPeriodic(MonotonicDuration::fromMSec(TimerPeriodMs100 * 100));
        }
        return res;
    }

    /**
     * Make the node unknown.
     */
    void forgetNode(NodeID node_id)
    {
        if (node_id.isValid())
        {
            Entry& entry = getEntry(node_id);
            entry = Entry();
        }
        else
        {
            UAVCAN_ASSERT(0);
        }
    }

    /**
     * Make all nodes unknown.
     */
    void forgetAllNodes()
    {
        for (unsigned i = 0; i < (sizeof(entries_) / sizeof(entries_[0])); i++)
        {
            entries_[i] = Entry();
        }
    }

    /**
     * Returns status of a given node.
     * Unknown nodes are considered offline.
     * Complexity O(1).
     */
    NodeStatus getNodeStatus(NodeID node_id) const
    {
        if (!node_id.isValid())
        {
            UAVCAN_ASSERT(0);
            return NodeStatus();
        }

        const Entry& entry = getEntry(node_id);
        if (entry.time_since_last_update_ms100 >= 0)
        {
            return entry.status;
        }
        else
        {
            return NodeStatus();
        }
    }

    /**
     * Whether the class has observed this node at least once since initialization.
     * Complexity O(1).
     */
    bool isNodeKnown(NodeID node_id) const
    {
        if (!node_id.isValid())
        {
            UAVCAN_ASSERT(0);
            return false;
        }
        return getEntry(node_id).time_since_last_update_ms100 >= 0;
    }

    /**
     * This helper method allows to quickly estimate the overall network health.
     * Health of the local node is not considered.
     * Returns an invalid Node ID value if there's no known nodes in the network.
     */
    NodeID findNodeWithWorstHealth() const
    {
        NodeID nid_with_worst_health;
        uint8_t worst_health = protocol::NodeStatus::HEALTH_OK;

        for (uint8_t i = 1; i <= NodeID::Max; i++)
        {
            const NodeID nid(i);
            UAVCAN_ASSERT(nid.isUnicast());
            const Entry& entry = getEntry(nid);
            if (entry.time_since_last_update_ms100 >= 0)
            {
                if (entry.status.health > worst_health || !nid_with_worst_health.isValid())
                {
                    nid_with_worst_health = nid;
                    worst_health = entry.status.health;
                }
            }
        }

        return nid_with_worst_health;
    }

    /**
     * Calls the operator for every known node.
     * Operator signature:
     *   void (NodeID, NodeStatus)
     */
    template <typename Operator>
    void forEachNode(Operator op) const
    {
        for (uint8_t i = 1; i <= NodeID::Max; i++)
        {
            const NodeID nid(i);
            UAVCAN_ASSERT(nid.isUnicast());
            const Entry& entry = getEntry(nid);
            if (entry.time_since_last_update_ms100 >= 0)
            {
                op(nid, entry.status);
            }
        }
    }
};

}

#endif // UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED
<commit_msg>NodeStatusMonitor: Fix to premature node timeout<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#ifndef UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED
#define UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED

#include <uavcan/debug.hpp>
#include <uavcan/util/method_binder.hpp>
#include <uavcan/node/subscriber.hpp>
#include <uavcan/node/timer.hpp>
#include <uavcan/protocol/NodeStatus.hpp>
#include <cassert>
#include <cstdlib>

namespace uavcan
{
/**
 * This class implements the core functionality of a network monitor.
 * It can be extended by inheritance to add more complex logic, or used directly as is.
 */
class UAVCAN_EXPORT NodeStatusMonitor
{
public:
    struct NodeStatus
    {
        uint8_t health   : 2;
        uint8_t mode     : 3;
        uint8_t sub_mode : 3;

        NodeStatus() :
            health(protocol::NodeStatus::HEALTH_CRITICAL),
            mode(protocol::NodeStatus::MODE_OFFLINE),
            sub_mode(0)
        {
            StaticAssert<protocol::NodeStatus::FieldTypes::health::BitLen   == 2>::check();
            StaticAssert<protocol::NodeStatus::FieldTypes::mode::BitLen     == 3>::check();
            StaticAssert<protocol::NodeStatus::FieldTypes::sub_mode::BitLen == 3>::check();
        }

        bool operator!=(const NodeStatus rhs) const { return !operator==(rhs); }
        bool operator==(const NodeStatus rhs) const
        {
            return std::memcmp(this, &rhs, sizeof(NodeStatus)) == 0;
        }

#if UAVCAN_TOSTRING
        std::string toString() const
        {
            char buf[40];
            (void)snprintf(buf, sizeof(buf), "health=%d mode=%d sub_mode=%d", int(health), int(mode), int(sub_mode));
            return std::string(buf);
        }
#endif
    };

    struct NodeStatusChangeEvent
    {
        NodeID node_id;
        NodeStatus status;
        NodeStatus old_status;
        bool was_known;

        NodeStatusChangeEvent() :
            was_known(false)
        { }
    };

private:
    enum { TimerPeriodMs100 = 2 };

    typedef MethodBinder<NodeStatusMonitor*,
                         void (NodeStatusMonitor::*)(const ReceivedDataStructure<protocol::NodeStatus>&)>
            NodeStatusCallback;

    typedef MethodBinder<NodeStatusMonitor*, void (NodeStatusMonitor::*)(const TimerEvent&)> TimerCallback;

    Subscriber<protocol::NodeStatus, NodeStatusCallback, MaxNetworkSizeHint, 0> sub_;

    TimerEventForwarder<TimerCallback> timer_;

    struct Entry
    {
        NodeStatus status;
        int8_t time_since_last_update_ms100;
        Entry() :
            time_since_last_update_ms100(-1)
        { }
    };

    mutable Entry entries_[NodeID::Max];  // [1, NodeID::Max]

    Entry& getEntry(NodeID node_id) const
    {
        if (node_id.get() < 1 || node_id.get() > NodeID::Max)
        {
            handleFatalError("NodeStatusMonitor NodeID");
        }
        return entries_[node_id.get() - 1];
    }

    void changeNodeStatus(const NodeID node_id, const Entry new_entry_value)
    {
        Entry& entry = getEntry(node_id);
        if (entry.status != new_entry_value.status)
        {
            NodeStatusChangeEvent event;
            event.node_id    = node_id;
            event.old_status = entry.status;
            event.status     = new_entry_value.status;
            event.was_known  = entry.time_since_last_update_ms100 >= 0;

            UAVCAN_TRACE("NodeStatusMonitor", "Node %i [%s] status change: [%s] --> [%s]", int(node_id.get()),
                         (event.was_known ? "known" : "new"),
                         event.old_status.toString().c_str(), event.status.toString().c_str());

            handleNodeStatusChange(event);
        }
        entry = new_entry_value;
    }

    void handleNodeStatus(const ReceivedDataStructure<protocol::NodeStatus>& msg)
    {
        Entry new_entry;
        new_entry.time_since_last_update_ms100 = 0;
        new_entry.status.health   = msg.health   & ((1 << protocol::NodeStatus::FieldTypes::health::BitLen) - 1);
        new_entry.status.mode     = msg.mode     & ((1 << protocol::NodeStatus::FieldTypes::mode::BitLen) - 1);
        new_entry.status.sub_mode = msg.sub_mode & ((1 << protocol::NodeStatus::FieldTypes::sub_mode::BitLen) - 1);

        changeNodeStatus(msg.getSrcNodeID(), new_entry);

        handleNodeStatusMessage(msg);
    }

    void handleTimerEvent(const TimerEvent&)
    {
        const int OfflineTimeoutMs100 = protocol::NodeStatus::OFFLINE_TIMEOUT_MS / 100;

        for (uint8_t i = 1; i <= NodeID::Max; i++)
        {
            Entry& entry = getEntry(i);
            if (entry.time_since_last_update_ms100 >= 0 &&
                entry.status.mode != protocol::NodeStatus::MODE_OFFLINE)
            {
                entry.time_since_last_update_ms100 =
                    int8_t(entry.time_since_last_update_ms100 + int8_t(TimerPeriodMs100));

                if (entry.time_since_last_update_ms100 > OfflineTimeoutMs100)
                {
                    Entry new_entry_value = entry;
                    new_entry_value.time_since_last_update_ms100 = OfflineTimeoutMs100;
                    new_entry_value.status.mode = protocol::NodeStatus::MODE_OFFLINE;
                    changeNodeStatus(i, new_entry_value);
                }
            }
        }
    }

protected:
    /**
     * Called when a node becomes online, changes status or goes offline.
     * Refer to uavcan.protocol.NodeStatus for the offline timeout value.
     * Overriding is not required.
     */
    virtual void handleNodeStatusChange(const NodeStatusChangeEvent& event)
    {
        (void)event;
    }

    /**
     * Called for every received message uavcan.protocol.NodeStatus after handleNodeStatusChange(), even
     * if the status code did not change.
     * Overriding is not required.
     */
    virtual void handleNodeStatusMessage(const ReceivedDataStructure<protocol::NodeStatus>& msg)
    {
        (void)msg;
    }

public:
    explicit NodeStatusMonitor(INode& node)
        : sub_(node)
        , timer_(node)
    { }

    virtual ~NodeStatusMonitor() { }

    /**
     * Starts the monitor.
     * Destroy the object to stop it.
     * Returns negative error code.
     */
    int start()
    {
        const int res = sub_.start(NodeStatusCallback(this, &NodeStatusMonitor::handleNodeStatus));
        if (res >= 0)
        {
            timer_.setCallback(TimerCallback(this, &NodeStatusMonitor::handleTimerEvent));
            timer_.startPeriodic(MonotonicDuration::fromMSec(TimerPeriodMs100 * 100));
        }
        return res;
    }

    /**
     * Make the node unknown.
     */
    void forgetNode(NodeID node_id)
    {
        if (node_id.isValid())
        {
            Entry& entry = getEntry(node_id);
            entry = Entry();
        }
        else
        {
            UAVCAN_ASSERT(0);
        }
    }

    /**
     * Make all nodes unknown.
     */
    void forgetAllNodes()
    {
        for (unsigned i = 0; i < (sizeof(entries_) / sizeof(entries_[0])); i++)
        {
            entries_[i] = Entry();
        }
    }

    /**
     * Returns status of a given node.
     * Unknown nodes are considered offline.
     * Complexity O(1).
     */
    NodeStatus getNodeStatus(NodeID node_id) const
    {
        if (!node_id.isValid())
        {
            UAVCAN_ASSERT(0);
            return NodeStatus();
        }

        const Entry& entry = getEntry(node_id);
        if (entry.time_since_last_update_ms100 >= 0)
        {
            return entry.status;
        }
        else
        {
            return NodeStatus();
        }
    }

    /**
     * Whether the class has observed this node at least once since initialization.
     * Complexity O(1).
     */
    bool isNodeKnown(NodeID node_id) const
    {
        if (!node_id.isValid())
        {
            UAVCAN_ASSERT(0);
            return false;
        }
        return getEntry(node_id).time_since_last_update_ms100 >= 0;
    }

    /**
     * This helper method allows to quickly estimate the overall network health.
     * Health of the local node is not considered.
     * Returns an invalid Node ID value if there's no known nodes in the network.
     */
    NodeID findNodeWithWorstHealth() const
    {
        NodeID nid_with_worst_health;
        uint8_t worst_health = protocol::NodeStatus::HEALTH_OK;

        for (uint8_t i = 1; i <= NodeID::Max; i++)
        {
            const NodeID nid(i);
            UAVCAN_ASSERT(nid.isUnicast());
            const Entry& entry = getEntry(nid);
            if (entry.time_since_last_update_ms100 >= 0)
            {
                if (entry.status.health > worst_health || !nid_with_worst_health.isValid())
                {
                    nid_with_worst_health = nid;
                    worst_health = entry.status.health;
                }
            }
        }

        return nid_with_worst_health;
    }

    /**
     * Calls the operator for every known node.
     * Operator signature:
     *   void (NodeID, NodeStatus)
     */
    template <typename Operator>
    void forEachNode(Operator op) const
    {
        for (uint8_t i = 1; i <= NodeID::Max; i++)
        {
            const NodeID nid(i);
            UAVCAN_ASSERT(nid.isUnicast());
            const Entry& entry = getEntry(nid);
            if (entry.time_since_last_update_ms100 >= 0)
            {
                op(nid, entry.status);
            }
        }
    }
};

}

#endif // UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "ReturnSynthesizer.h"

#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace cling {
  ReturnSynthesizer::ReturnSynthesizer(clang::Sema* S)
    : TransactionTransformer(S), m_Context(&S->getASTContext()) {
  }

  // pin the vtable here.
  ReturnSynthesizer::~ReturnSynthesizer()
  { }

  void ReturnSynthesizer::Transform() {
    if (!getTransaction()->getCompilationOpts().ResultEvaluation)
      return;

    for (Transaction::const_iterator iDGR = getTransaction()->decls_begin(),
           eDGR = getTransaction()->decls_end(); iDGR != eDGR; ++iDGR)
      for (DeclGroupRef::const_iterator I = (*iDGR).begin(), E = (*iDGR).end();
           I != E; ++I)
        if (FunctionDecl* FD = dyn_cast<FunctionDecl>(*I)) {
          if (!utils::Analyze::IsWrapper(FD))
            continue;

          int foundAtPos = -1;
          Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos,
                                                               /*omitDS*/false,
                                                               m_Sema);
          if (lastExpr) {
            QualType RetTy = lastExpr->getType();
            if (!RetTy->isVoidType()) {
              // Change the void function's return type
              // We can't PushDeclContext, because we don't have scope.
              Sema::ContextRAII pushedDC(*m_Sema, FD);
              FunctionProtoType::ExtProtoInfo EPI;
              QualType FnTy = m_Context->getFunctionType(RetTy,
                                                         /* ArgArray = */0,
                                                         /* NumArgs = */0, EPI);
              FD->setType(FnTy);
              CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
              assert(CS && "Missing body?");
              // Change it with return stmt (Avoid dealloc/alloc of all el.)
              *(CS->body_begin() + foundAtPos)
                = m_Sema->ActOnReturnStmt(lastExpr->getExprLoc(),
                                            lastExpr).take();
            }
          }
        }
  }
} // end namespace cling
<commit_msg>If the last statement is not an expression, check whether it's a return statement. If it is, remove the implicit-cast-to-void (injected by Sema to heal "return 12" for the original void return type of the wrapper) and adapt the return type of the wrapper to the type of the returned expression. I.e. void wrap() { return (void)12;} will be converted to int wrap() { return 12;}<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "ReturnSynthesizer.h"

#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace cling {
  ReturnSynthesizer::ReturnSynthesizer(clang::Sema* S)
    : TransactionTransformer(S), m_Context(&S->getASTContext()) {
  }

  // pin the vtable here.
  ReturnSynthesizer::~ReturnSynthesizer()
  { }

  void ReturnSynthesizer::Transform() {
    if (!getTransaction()->getCompilationOpts().ResultEvaluation)
      return;

    FunctionDecl* FD = getTransaction()->getWrapperFD();

    int foundAtPos = -1;
    Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos,
                                                         /*omitDS*/false,
                                                         m_Sema);
    if (lastExpr) {
      QualType RetTy = lastExpr->getType();
      if (!RetTy->isVoidType()) {
        // Change the void function's return type
        // We can't PushDeclContext, because we don't have scope.
        Sema::ContextRAII pushedDC(*m_Sema, FD);
        FunctionProtoType::ExtProtoInfo EPI;
        QualType FnTy = m_Context->getFunctionType(RetTy,
                                                   /* ArgArray = */0,
                                                   /* NumArgs = */0, EPI);
        FD->setType(FnTy);
        CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
        assert(CS && "Missing body?");
        // Change it to a return stmt (Avoid dealloc/alloc of all el.)
        *(CS->body_begin() + foundAtPos)
          = m_Sema->ActOnReturnStmt(lastExpr->getExprLoc(),
                                    lastExpr).take();
      }
    } else if (foundAtPos >= 0) {
      // check for non-void return statement
      CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
      Stmt* CSS = *(CS->body_begin() + foundAtPos);
      if (ReturnStmt* RS = dyn_cast<ReturnStmt>(CSS)) {
        if (Expr* RetV = RS->getRetValue()) {
          QualType RetTy = RetV->getType();
          // Any return statement will have been "healed" by Sema
          // to correspond to the original void return type of the
          // wrapper, using a ImplicitCastExpr 'void' <ToVoid>.
          // Remove that.
          if (RetTy->isVoidType()) {
            ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RetV);
            if (VoidCast) {
              RS->setRetValue(VoidCast->getSubExpr());
              RetTy = VoidCast->getSubExpr()->getType();
            }
          }

          if (!RetTy->isVoidType()) {
            Sema::ContextRAII pushedDC(*m_Sema, FD);
            FunctionProtoType::ExtProtoInfo EPI;
            QualType FnTy = m_Context->getFunctionType(RetTy,
                                                       /* ArgArray = */0,
                                                       /* NumArgs = */0,
                                                       EPI);
            FD->setType(FnTy);
          } // not returning void
        } // have return value
      } // is a return statement
    } // have a statement
  }
} // end namespace cling
<|endoftext|>