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

#include <sensor_msgs/PointCloud2.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
#include <pcl/kdtree/kdtree_flann.h>

using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;

std::string default_correspondence_type = "index";

void
printHelp (int argc, char **argv)
{
  print_error ("Syntax is: %s source.pcd target.pcd output_intensity.pcd <options>\n", argv[0]);
  print_info ("  where options are:\n");
  print_info ("                     -correspondence X = the way of selecting the corresponding pair in the target cloud for the current point in the source cloud\n");
  print_info ("                                         options are: index = points with identical indices are paired together. Note: both clouds need to have the same number of points\n");
  print_info ("                                                      nn = source point is paired with its nearest neighbor in the target cloud\n");
  print_info ("                                                      nnplane = source point is paired with its projection on the plane determined by the nearest neighbor in the target cloud. Note: target cloud needs to contain normals\n");
  print_info ("                                         (default: ");
  print_value ("%s", default_correspondence_type.c_str ()); print_info (")\n");
}

bool
loadCloud (const std::string &filename, sensor_msgs::PointCloud2 &cloud)
{
  TicToc tt;
//  print_highlight ("Loading "); print_value ("%s ", filename.c_str ());

  tt.tic ();
  if (loadPCDFile (filename, cloud) < 0)
    return (false);
//  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" seconds : "); print_value ("%d", cloud.width * cloud.height); print_info (" points]\n");
//  print_info ("Available dimensions: "); print_value ("%s\n", pcl::getFieldsList (cloud).c_str ());

  return (true);
}

void
compute (const sensor_msgs::PointCloud2::ConstPtr &cloud_source, const sensor_msgs::PointCloud2::ConstPtr &cloud_target,
         sensor_msgs::PointCloud2 &output, std::string correspondence_type)
{
  // Estimate
  TicToc tt;
  tt.tic ();

  PointCloud<PointXYZ>::Ptr xyz_source (new PointCloud<PointXYZ> ());
  fromROSMsg (*cloud_source, *xyz_source);
  PointCloud<PointXYZ>::Ptr xyz_target (new PointCloud<PointXYZ> ());
  fromROSMsg (*cloud_target, *xyz_target);

  PointCloud<PointXYZI>::Ptr output_xyzi (new PointCloud<PointXYZI> ());
  output_xyzi->points.resize (xyz_source->points.size ());
  output_xyzi->height = cloud_source->height;
  output_xyzi->width = cloud_source->width;

  float rmse = 0.0f;

  if (correspondence_type == "index")
  {
//    print_highlight (stderr, "Computing using the equal indices correspondence heuristic.\n");

    if (xyz_source->points.size () != xyz_target->points.size ())
    {
      print_error ("Source and target clouds do not have the same number of points.\n");
      return;
    }

    for (size_t point_i = 0; point_i < xyz_source->points.size (); ++point_i)
    {
      float dist = squaredEuclideanDistance (xyz_source->points[point_i], xyz_target->points[point_i]);
      rmse += dist;

      output_xyzi->points[point_i].x = xyz_source->points[point_i].x;
      output_xyzi->points[point_i].y = xyz_source->points[point_i].y;
      output_xyzi->points[point_i].z = xyz_source->points[point_i].z;
      output_xyzi->points[point_i].intensity = dist;
    }
    rmse = sqrt (rmse / xyz_source->points.size ());
  }
  else if (correspondence_type == "nn")
  {
//    print_highlight (stderr, "Computing using the nearest neighbor correspondence heuristic.\n");

    KdTreeFLANN<PointXYZ>::Ptr tree (new KdTreeFLANN<PointXYZ> ());
    tree->setInputCloud (xyz_target);

    for (size_t point_i = 0; point_i < xyz_source->points.size (); ++ point_i)
    {
      std::vector<int> nn_indices (1);
      std::vector<float> nn_distances (1);
      tree->nearestKSearch (point_i, 1, nn_indices, nn_distances);
      size_t point_nn_i = nn_indices.front();

      float dist = squaredEuclideanDistance (xyz_source->points[point_i], xyz_target->points[point_nn_i]);
      rmse += dist;

      output_xyzi->points[point_i].x = xyz_source->points[point_i].x;
      output_xyzi->points[point_i].y = xyz_source->points[point_i].y;
      output_xyzi->points[point_i].z = xyz_source->points[point_i].z;
      output_xyzi->points[point_i].intensity = dist;
    }
    rmse = sqrt (rmse / xyz_source->points.size ());

  }
  else if (correspondence_type == "nnplane")
  {
//    print_highlight (stderr, "Computing using the nearest neighbor plane projection correspondence heuristic.\n");

    PointCloud<Normal>::Ptr normals_target (new PointCloud<Normal> ());
    fromROSMsg (*cloud_target, *normals_target);

    KdTreeFLANN<PointXYZ>::Ptr tree (new KdTreeFLANN<PointXYZ> ());
    tree->setInputCloud (xyz_target);

    for (size_t point_i = 0; point_i < xyz_source->points.size (); ++ point_i)
    {
      std::vector<int> nn_indices (1);
      std::vector<float> nn_distances (1);
      tree->nearestKSearch (point_i, 1, nn_indices, nn_distances);
      size_t point_nn_i = nn_indices.front();

      Eigen::Vector3f normal_target = normals_target->points[point_nn_i].getNormalVector3fMap (),
          point_source = xyz_source->points[point_i].getVector3fMap (),
          point_target = xyz_target->points[point_nn_i].getVector3fMap ();

      float dist = normal_target.dot (point_source - point_target);
      rmse += dist * dist;

      output_xyzi->points[point_i].x = xyz_source->points[point_i].x;
      output_xyzi->points[point_i].y = xyz_source->points[point_i].y;
      output_xyzi->points[point_i].z = xyz_source->points[point_i].z;
      output_xyzi->points[point_i].intensity = dist * dist;
    }
    rmse = sqrt (rmse / xyz_source->points.size ());
  }
  else
  {
    print_error ("Unrecognized correspondence type. Check legal arguments by using the -h option\n");
    return;
  }

  toROSMsg (*output_xyzi, output);

// print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" seconds]\n");
  print_highlight ("RMSE Error: %f\n", rmse);
}

void
saveCloud (const std::string &filename, const sensor_msgs::PointCloud2 &output)
{
  TicToc tt;
  tt.tic ();

//  print_highlight ("Saving "); print_value ("%s ", filename.c_str ());

  pcl::io::savePCDFile (filename, output);

//  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" seconds : "); print_value ("%d", output.width * output.height); print_info (" points]\n");
}

/* ---[ */
int
main (int argc, char** argv)
{
//  print_info ("Compute the differences between two point clouds and visualizing them as an output intensity cloud. For more information, use: %s -h\n", argv[0]);

  if (argc < 4)
  {
    printHelp (argc, argv);
    return (-1);
  }

  // Parse the command line arguments for .pcd files
  std::vector<int> p_file_indices;
  p_file_indices = parse_file_extension_argument (argc, argv, ".pcd");
  if (p_file_indices.size () != 3)
  {
    print_error ("Need two input PCD files and one output PCD file to continue.\n");
    return (-1);
  }

  // Command line parsing
  std::string correspondence_type = default_correspondence_type;
  parse_argument (argc, argv, "-correspondence", correspondence_type);

  // Load the first file
  sensor_msgs::PointCloud2::Ptr cloud_source (new sensor_msgs::PointCloud2 ());
  if (!loadCloud (argv[p_file_indices[0]], *cloud_source))
    return (-1);
  // Load the second file
  sensor_msgs::PointCloud2::Ptr cloud_target (new sensor_msgs::PointCloud2 ());
  if (!loadCloud (argv[p_file_indices[1]], *cloud_target))
    return (-1);

  sensor_msgs::PointCloud2 output;
  // Perform the feature estimation
  compute (cloud_source, cloud_target, output, correspondence_type);

  // Output the third file
  saveCloud (argv[p_file_indices[2]], output);
}
<commit_msg>compute_cloud_error tool can now handle nan points in the input clouds<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */

#include <sensor_msgs/PointCloud2.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
#include <pcl/kdtree/kdtree_flann.h>

using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;

std::string default_correspondence_type = "index";

void
printHelp (int argc, char **argv)
{
  print_error ("Syntax is: %s source.pcd target.pcd output_intensity.pcd <options>\n", argv[0]);
  print_info ("  where options are:\n");
  print_info ("                     -correspondence X = the way of selecting the corresponding pair in the target cloud for the current point in the source cloud\n");
  print_info ("                                         options are: index = points with identical indices are paired together. Note: both clouds need to have the same number of points\n");
  print_info ("                                                      nn = source point is paired with its nearest neighbor in the target cloud\n");
  print_info ("                                                      nnplane = source point is paired with its projection on the plane determined by the nearest neighbor in the target cloud. Note: target cloud needs to contain normals\n");
  print_info ("                                         (default: ");
  print_value ("%s", default_correspondence_type.c_str ()); print_info (")\n");
}

bool
loadCloud (const std::string &filename, sensor_msgs::PointCloud2 &cloud)
{
  TicToc tt;
  print_highlight ("Loading "); print_value ("%s ", filename.c_str ());

  tt.tic ();
  if (loadPCDFile (filename, cloud) < 0)
    return (false);
  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" seconds : "); print_value ("%d", cloud.width * cloud.height); print_info (" points]\n");
  print_info ("Available dimensions: "); print_value ("%s\n", pcl::getFieldsList (cloud).c_str ());

  return (true);
}

void
compute (const sensor_msgs::PointCloud2::ConstPtr &cloud_source, const sensor_msgs::PointCloud2::ConstPtr &cloud_target,
         sensor_msgs::PointCloud2 &output, std::string correspondence_type)
{
  // Estimate
  TicToc tt;
  tt.tic ();

  PointCloud<PointXYZ>::Ptr xyz_source (new PointCloud<PointXYZ> ());
  fromROSMsg (*cloud_source, *xyz_source);
  PointCloud<PointXYZ>::Ptr xyz_target (new PointCloud<PointXYZ> ());
  fromROSMsg (*cloud_target, *xyz_target);

  PointCloud<PointXYZI>::Ptr output_xyzi (new PointCloud<PointXYZI> ());
  output_xyzi->points.resize (xyz_source->points.size ());
  output_xyzi->height = cloud_source->height;
  output_xyzi->width = cloud_source->width;

  float rmse = 0.0f;

  if (correspondence_type == "index")
  {
    print_highlight (stderr, "Computing using the equal indices correspondence heuristic.\n");

    if (xyz_source->points.size () != xyz_target->points.size ())
    {
      print_error ("Source and target clouds do not have the same number of points.\n");
      return;
    }

    for (size_t point_i = 0; point_i < xyz_source->points.size (); ++point_i)
    {
      if (!pcl_isfinite (xyz_source->points[point_i].x) || !pcl_isfinite (xyz_source->points[point_i].y) || !pcl_isfinite (xyz_source->points[point_i].z))
        continue;
      if (!pcl_isfinite (xyz_target->points[point_i].x) || !pcl_isfinite (xyz_target->points[point_i].y) || !pcl_isfinite (xyz_target->points[point_i].z))
        continue;

      float dist = squaredEuclideanDistance (xyz_source->points[point_i], xyz_target->points[point_i]);
      rmse += dist;

      output_xyzi->points[point_i].x = xyz_source->points[point_i].x;
      output_xyzi->points[point_i].y = xyz_source->points[point_i].y;
      output_xyzi->points[point_i].z = xyz_source->points[point_i].z;
      output_xyzi->points[point_i].intensity = dist;
    }
    rmse = sqrt (rmse / xyz_source->points.size ());
  }
  else if (correspondence_type == "nn")
  {
    print_highlight (stderr, "Computing using the nearest neighbor correspondence heuristic.\n");

    KdTreeFLANN<PointXYZ>::Ptr tree (new KdTreeFLANN<PointXYZ> ());
    tree->setInputCloud (xyz_target);

    for (size_t point_i = 0; point_i < xyz_source->points.size (); ++ point_i)
    {
      if (!pcl_isfinite (xyz_source->points[point_i].x) || !pcl_isfinite (xyz_source->points[point_i].y) || !pcl_isfinite (xyz_source->points[point_i].z))
        continue;

      std::vector<int> nn_indices (1);
      std::vector<float> nn_distances (1);
      if (!tree->nearestKSearch (point_i, 1, nn_indices, nn_distances))
        continue;
      size_t point_nn_i = nn_indices.front();

      float dist = squaredEuclideanDistance (xyz_source->points[point_i], xyz_target->points[point_nn_i]);
      rmse += dist;

      output_xyzi->points[point_i].x = xyz_source->points[point_i].x;
      output_xyzi->points[point_i].y = xyz_source->points[point_i].y;
      output_xyzi->points[point_i].z = xyz_source->points[point_i].z;
      output_xyzi->points[point_i].intensity = dist;
    }
    rmse = sqrt (rmse / xyz_source->points.size ());

  }
  else if (correspondence_type == "nnplane")
  {
    print_highlight (stderr, "Computing using the nearest neighbor plane projection correspondence heuristic.\n");

    PointCloud<Normal>::Ptr normals_target (new PointCloud<Normal> ());
    fromROSMsg (*cloud_target, *normals_target);

    KdTreeFLANN<PointXYZ>::Ptr tree (new KdTreeFLANN<PointXYZ> ());
    tree->setInputCloud (xyz_target);

    for (size_t point_i = 0; point_i < xyz_source->points.size (); ++ point_i)
    {
      if (!pcl_isfinite (xyz_source->points[point_i].x) || !pcl_isfinite (xyz_source->points[point_i].y) || !pcl_isfinite (xyz_source->points[point_i].z))
        continue;

      std::vector<int> nn_indices (1);
      std::vector<float> nn_distances (1);
      if (!tree->nearestKSearch (point_i, 1, nn_indices, nn_distances))
        continue;
      size_t point_nn_i = nn_indices.front();

      Eigen::Vector3f normal_target = normals_target->points[point_nn_i].getNormalVector3fMap (),
          point_source = xyz_source->points[point_i].getVector3fMap (),
          point_target = xyz_target->points[point_nn_i].getVector3fMap ();

      float dist = normal_target.dot (point_source - point_target);
      rmse += dist * dist;

      output_xyzi->points[point_i].x = xyz_source->points[point_i].x;
      output_xyzi->points[point_i].y = xyz_source->points[point_i].y;
      output_xyzi->points[point_i].z = xyz_source->points[point_i].z;
      output_xyzi->points[point_i].intensity = dist * dist;
    }
    rmse = sqrt (rmse / xyz_source->points.size ());
  }
  else
  {
    print_error ("Unrecognized correspondence type. Check legal arguments by using the -h option\n");
    return;
  }

  toROSMsg (*output_xyzi, output);

  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" seconds]\n");
  print_highlight ("RMSE Error: %f\n", rmse);
}

void
saveCloud (const std::string &filename, const sensor_msgs::PointCloud2 &output)
{
  TicToc tt;
  tt.tic ();

  print_highlight ("Saving "); print_value ("%s ", filename.c_str ());

  pcl::io::savePCDFile (filename, output);

  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" seconds : "); print_value ("%d", output.width * output.height); print_info (" points]\n");
}

/* ---[ */
int
main (int argc, char** argv)
{
  print_info ("Compute the differences between two point clouds and visualizing them as an output intensity cloud. For more information, use: %s -h\n", argv[0]);

  if (argc < 4)
  {
    printHelp (argc, argv);
    return (-1);
  }

  // Parse the command line arguments for .pcd files
  std::vector<int> p_file_indices;
  p_file_indices = parse_file_extension_argument (argc, argv, ".pcd");
  if (p_file_indices.size () != 3)
  {
    print_error ("Need two input PCD files and one output PCD file to continue.\n");
    return (-1);
  }

  // Command line parsing
  std::string correspondence_type = default_correspondence_type;
  parse_argument (argc, argv, "-correspondence", correspondence_type);

  // Load the first file
  sensor_msgs::PointCloud2::Ptr cloud_source (new sensor_msgs::PointCloud2 ());
  if (!loadCloud (argv[p_file_indices[0]], *cloud_source))
    return (-1);
  // Load the second file
  sensor_msgs::PointCloud2::Ptr cloud_target (new sensor_msgs::PointCloud2 ());
  if (!loadCloud (argv[p_file_indices[1]], *cloud_target))
    return (-1);

  sensor_msgs::PointCloud2 output;
  // Perform the feature estimation
  compute (cloud_source, cloud_target, output, correspondence_type);

  // Output the third file
  saveCloud (argv[p_file_indices[2]], output);
}
<|endoftext|>


<commit_before>/* Copyright (c) 2017 Hans-Kristian Arntzen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "lights.hpp"
#include "render_queue.hpp"
#include "render_context.hpp"
#include "shader_suite.hpp"
#include "device.hpp"

using namespace Vulkan;
using namespace Util;

namespace Granite
{
PositionalLight::PositionalLight(Type type)
	: type(type)
{
}

void PositionalLight::set_color(vec3 color)
{
	this->color = color;
	recompute_range();
}

void PositionalLight::set_falloff(float constant, float linear, float quadratic)
{
	this->constant = max(constant, 0.0f);
	this->linear = max(linear, 0.0f);
	this->quadratic = max(quadratic, 0.0f);
	recompute_range();
}

void PositionalLight::set_maximum_range(float range)
{
	maximum_range = range;
	recompute_range();
}

void PositionalLight::recompute_range()
{
	if (linear == 0.0f && quadratic == 0.0f)
	{
		set_range(maximum_range);
		return;
	}

	// Check when attenuation drops below a constant.
	const float target_atten = 0.01f;
	float max_color = max(max(color.r, color.g), color.b);

	if (max_color < target_atten * constant)
	{
		set_range(0.0001f);
		return;
	}

	float a = quadratic;
	float b = linear;
	float c = constant - max_color / target_atten;
	float d = (-b + sqrt(b * b - 4.0f * a * c)) / (2.0f * a);
	set_range(d);
}

void SpotLight::set_spot_parameters(float inner_cone, float outer_cone)
{
	this->inner_cone = clamp(inner_cone, 0.001f, 1.0f);
	this->outer_cone = clamp(outer_cone, 0.001f, 1.0f);
	recompute_range();
}

void SpotLight::set_range(float range)
{
	this->range = range;
	float min_z = -range;
	float xy = range * sqrt(1.0f - outer_cone * outer_cone) / outer_cone;
	xy_range = xy;
	aabb = AABB(vec3(-xy, -xy, min_z), vec3(xy, xy, 0.0f));
}

PositionalFragmentInfo SpotLight::get_shader_info(const mat4 &transform) const
{
	return {
			vec4(color, outer_cone),
			vec4(constant, linear, quadratic, 1.0f / range),
			vec4(transform[3].xyz(), inner_cone),
			vec4(normalize(transform[2].xyz()), xy_range),
	};
}

SpotLight::SpotLight()
	: PositionalLight(PositionalLight::Type::Spot)
{
}

struct SpotLightRenderInfo
{
	Program *program = nullptr;
	const Buffer *vbo = nullptr;
	const Buffer *ibo = nullptr;
	unsigned count = 0;

	struct Push
	{
		mat4 inv_view_projection;
		vec4 camera_pos;
		vec2 inv_resolution;
	} push;
};

struct PositionalVertexInfo
{
	mat4 model;
};

struct PositionalShaderInfo
{
	PositionalVertexInfo vertex;
	PositionalFragmentInfo fragment;
};

struct LightMesh : public EventHandler
{
	LightMesh()
	{
		EVENT_MANAGER_REGISTER_LATCH(LightMesh, on_device_created, on_device_destroyed, DeviceCreatedEvent);
	}

	Vulkan::BufferHandle spot_vbo;
	Vulkan::BufferHandle spot_ibo;
	unsigned spot_count = 0;

	void on_device_created(const Vulkan::DeviceCreatedEvent &e)
	{
		static const vec3 positions[] = {
			vec3(0.0f, 0.0f, 0.0f),
			vec3(-1.0f, -1.0f, -1.0f),
			vec3(+1.0f, -1.0f, -1.0f),
			vec3(-1.0f, +1.0f, -1.0f),
			vec3(+1.0f, +1.0f, -1.0f),
		};

		static const uint16_t indices[] = {
			1, 0, 3,
			0, 2, 4,
			0, 4, 3,
			0, 1, 2,
			4, 2, 3,
			2, 1, 3,
		};

		spot_count = sizeof(indices) / sizeof(indices[0]);

		BufferCreateInfo info = {};
		info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
		info.size = sizeof(positions);
		info.domain = BufferDomain::Device;
		spot_vbo = e.get_device().create_buffer(info, positions);

		info.size = sizeof(indices);
		info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
		spot_ibo = e.get_device().create_buffer(info, indices);
	};

	void on_device_destroyed(const DeviceCreatedEvent &)
	{
		spot_vbo.reset();
		spot_ibo.reset();
	}
};
static LightMesh light_mesh;

static void spot_render_full_screen(CommandBuffer &cmd, const RenderQueueData *infos, unsigned num_instances)
{
	auto &spot_info = *static_cast<const SpotLightRenderInfo *>(infos[0].render_info);
	cmd.set_program(*spot_info.program);
	CommandBufferUtil::set_quad_vertex_state(cmd);
	cmd.set_cull_mode(VK_CULL_MODE_NONE);
	cmd.set_primitive_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);

	auto push = spot_info.push;
	push.inv_resolution = vec2(1.0f / cmd.get_viewport().width, 1.0f / cmd.get_viewport().height);
	cmd.push_constants(&push, 0, sizeof(push));

	for (unsigned i = 0; i < num_instances; )
	{
		unsigned to_render = min(256u, num_instances - i);

		auto *frag = static_cast<PositionalFragmentInfo *>(cmd.allocate_constant_data(2, 0,
		                                                                              sizeof(PositionalFragmentInfo) * to_render));
		auto *vert = static_cast<PositionalVertexInfo *>(cmd.allocate_constant_data(2, 1,
		                                                                            sizeof(PositionalVertexInfo) * to_render));

		for (unsigned j = 0; j < to_render; j++)
		{
			vert[j] = static_cast<const PositionalShaderInfo *>(infos[i + j].instance_data)->vertex;
			frag[j] = static_cast<const PositionalShaderInfo *>(infos[i + j].instance_data)->fragment;
		}

		cmd.draw(4, to_render);
		i += to_render;
	}
}

static void spot_render_common(CommandBuffer &cmd, const RenderQueueData *infos, unsigned num_instances)
{
	auto &spot_info = *static_cast<const SpotLightRenderInfo *>(infos[0].render_info);
	cmd.set_program(*spot_info.program);
	cmd.set_vertex_binding(0, *spot_info.vbo, 0, sizeof(vec3));
	cmd.set_vertex_attrib(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0);
	cmd.set_index_buffer(*spot_info.ibo, 0, VK_INDEX_TYPE_UINT16);

	auto push = spot_info.push;
	push.inv_resolution = vec2(1.0f / cmd.get_viewport().width, 1.0f / cmd.get_viewport().height);
	cmd.push_constants(&push, 0, sizeof(push));

	for (unsigned i = 0; i < num_instances; )
	{
		unsigned to_render = min(256u, num_instances - i);
		auto *frag = static_cast<PositionalFragmentInfo *>(cmd.allocate_constant_data(2, 0,
		                                                                              sizeof(PositionalFragmentInfo) * to_render));
		auto *vert = static_cast<PositionalVertexInfo *>(cmd.allocate_constant_data(2, 1,
		                                                                            sizeof(PositionalVertexInfo) * to_render));

		for (unsigned j = 0; j < to_render; j++)
		{
			vert[j] = static_cast<const PositionalShaderInfo *>(infos[i + j].instance_data)->vertex;
			frag[j] = static_cast<const PositionalShaderInfo *>(infos[i + j].instance_data)->fragment;
		}

		cmd.draw_indexed(spot_info.count, to_render);
		i += to_render;
	}
}

static void spot_render_front(CommandBuffer &cmd, const RenderQueueData *infos, unsigned num_instances)
{
	cmd.set_cull_mode(VK_CULL_MODE_BACK_BIT);
	spot_render_common(cmd, infos, num_instances);
}

static void spot_render_back(CommandBuffer &cmd, const RenderQueueData *infos, unsigned num_instances)
{
	cmd.set_cull_mode(VK_CULL_MODE_FRONT_BIT);
	cmd.set_depth_compare(VK_COMPARE_OP_GREATER);
	spot_render_common(cmd, infos, num_instances);
}

void SpotLight::get_render_info(const RenderContext &context, const CachedSpatialTransformComponent *transform,
                                RenderQueue &queue) const
{
	auto &params = context.get_render_parameters();
	auto &aabb = transform->world_aabb;
	float to_center = dot(aabb.get_center() - params.camera_position, params.camera_front);
	float radius = aabb.get_radius();
	float aabb_near = to_center - params.z_near - radius;
	float aabb_far = to_center + radius - params.z_far;

	RenderFunc func;

	if (aabb_near < 0.0f) // We risk clipping into the mesh, and since we can't rely on depthClamp, use backface.
	{
		if (aabb_far > 0.0f) // We risk clipping into far plane as well ... Use a full-screen quad.
			func = spot_render_full_screen;
		else
			func = spot_render_back;
	}
	else
		func = spot_render_front;

	Hasher h;
	auto instance_key = h.get();
	h.pointer(func);
	auto sorting_key = h.get();

	auto *spot = queue.allocate_one<PositionalShaderInfo>();
	spot->vertex.model = transform->transform->world_transform * scale(vec3(xy_range, xy_range, range));
	spot->fragment = get_shader_info(transform->transform->world_transform);

	auto *spot_info = queue.push<SpotLightRenderInfo>(Queue::Light, instance_key, sorting_key,
	                                                  func, spot);

	if (spot_info)
	{
		SpotLightRenderInfo info;

		info.count = light_mesh.spot_count;
		info.vbo = light_mesh.spot_vbo.get();
		info.ibo = light_mesh.spot_ibo.get();

		info.push.inv_view_projection = params.inv_view_projection;
		info.push.camera_pos = vec4(params.camera_position, 0.0f);

		info.program = queue.get_shader_suites()[ecast(RenderableType::SpotLight)].get_program(DrawPipeline::AlphaBlend, 0, 0,
		                                                                              func == spot_render_full_screen ? 1 : 0).get();
		*spot_info = info;
	}
}

PointLight::PointLight()
	: PositionalLight(PositionalLight::Type::Point)
{
}

void PointLight::set_range(float range)
{
	this->range = range;
	aabb = AABB(vec3(-range), vec3(range));
}

PositionalFragmentInfo PointLight::get_shader_info(const mat4 &transform) const
{
	return {
			vec4(color, 0.0f),
			vec4(constant, linear, quadratic, 1.0f / range),
			vec4(transform[3].xyz(), 0.0f),
			vec4(normalize(transform[2].xyz()), 0.0f),
	};
}

void PointLight::get_render_info(const RenderContext &context, const CachedSpatialTransformComponent *transform,
                                 RenderQueue &queue) const
{
	(void)context;
	(void)transform;
	(void)queue;
}

}<commit_msg>Use a better spot light mesh.<commit_after>/* Copyright (c) 2017 Hans-Kristian Arntzen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "lights.hpp"
#include "render_queue.hpp"
#include "render_context.hpp"
#include "shader_suite.hpp"
#include "device.hpp"

using namespace Vulkan;
using namespace Util;

namespace Granite
{
PositionalLight::PositionalLight(Type type)
	: type(type)
{
}

void PositionalLight::set_color(vec3 color)
{
	this->color = color;
	recompute_range();
}

void PositionalLight::set_falloff(float constant, float linear, float quadratic)
{
	this->constant = max(constant, 0.0f);
	this->linear = max(linear, 0.0f);
	this->quadratic = max(quadratic, 0.0f);
	recompute_range();
}

void PositionalLight::set_maximum_range(float range)
{
	maximum_range = range;
	recompute_range();
}

void PositionalLight::recompute_range()
{
	if (linear == 0.0f && quadratic == 0.0f)
	{
		set_range(maximum_range);
		return;
	}

	// Check when attenuation drops below a constant.
	const float target_atten = 0.01f;
	float max_color = max(max(color.r, color.g), color.b);

	if (max_color < target_atten * constant)
	{
		set_range(0.0001f);
		return;
	}

	float a = quadratic;
	float b = linear;
	float c = constant - max_color / target_atten;
	float d = (-b + sqrt(b * b - 4.0f * a * c)) / (2.0f * a);
	set_range(min(d, maximum_range));
}

void SpotLight::set_spot_parameters(float inner_cone, float outer_cone)
{
	this->inner_cone = clamp(inner_cone, 0.001f, 1.0f);
	this->outer_cone = clamp(outer_cone, 0.001f, 1.0f);
	recompute_range();
}

void SpotLight::set_range(float range)
{
	this->range = range;
	float min_z = -range;
	float xy = range * sqrt(1.0f - outer_cone * outer_cone) / outer_cone;
	xy_range = xy;
	aabb = AABB(vec3(-xy, -xy, min_z), vec3(xy, xy, 0.0f));
}

PositionalFragmentInfo SpotLight::get_shader_info(const mat4 &transform) const
{
	return {
		vec4(color, outer_cone),
		vec4(constant, linear, quadratic, 1.0f / range),
		vec4(transform[3].xyz(), inner_cone),
		vec4(normalize(transform[2].xyz()), xy_range),
	};
}

SpotLight::SpotLight()
	: PositionalLight(PositionalLight::Type::Spot)
{
}

struct SpotLightRenderInfo
{
	Program *program = nullptr;
	const Buffer *vbo = nullptr;
	const Buffer *ibo = nullptr;
	unsigned count = 0;

	struct Push
	{
		mat4 inv_view_projection;
		vec4 camera_pos;
		vec2 inv_resolution;
	} push;
};

struct PositionalVertexInfo
{
	mat4 model;
};

struct PositionalShaderInfo
{
	PositionalVertexInfo vertex;
	PositionalFragmentInfo fragment;
};

struct LightMesh : public EventHandler
{
	LightMesh()
	{
		EVENT_MANAGER_REGISTER_LATCH(LightMesh, on_device_created, on_device_destroyed, DeviceCreatedEvent);
	}

	Vulkan::BufferHandle spot_vbo;
	Vulkan::BufferHandle spot_ibo;
	unsigned spot_count = 0;

	void on_device_created(const Vulkan::DeviceCreatedEvent &e)
	{
		vec3 positions[17 + 2];
		positions[0] = vec3(0.0f);
		positions[1] = vec3(0.0f, 0.0f, -1.0f);

		float half_angle = 2.0f * pi<float>() / 32.0f;
		float padding_mod = 1.0f / cos(half_angle);

		for (unsigned i = 0; i <= 16; i++)
		{
			float rad = 2.0f * pi<float>() * float(i) / 16.0f;
			positions[i + 2] = vec3(padding_mod * cos(rad), padding_mod * sin(rad), -1.0f);
		}

		std::vector<uint16_t> indices;
		indices.reserve(2 * 3 * 16);
		for (unsigned i = 0; i < 16; i++)
		{
			indices.push_back(0);
			indices.push_back((i & 15) + 2);
			indices.push_back(((i + 1) & 15) + 2);
		}

		for (unsigned i = 0; i < 16; i++)
		{
			indices.push_back(1);
			indices.push_back(((i + 1) & 15) + 2);
			indices.push_back((i & 15) + 2);
		}

		spot_count = indices.size();

		BufferCreateInfo info = {};
		info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
		info.size = sizeof(positions);
		info.domain = BufferDomain::Device;
		spot_vbo = e.get_device().create_buffer(info, positions);

		info.size = indices.size() * sizeof(uint16_t);
		info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
		spot_ibo = e.get_device().create_buffer(info, indices.data());
	};

	void on_device_destroyed(const DeviceCreatedEvent &)
	{
		spot_vbo.reset();
		spot_ibo.reset();
	}
};
static LightMesh light_mesh;

static void spot_render_full_screen(CommandBuffer &cmd, const RenderQueueData *infos, unsigned num_instances)
{
	auto &spot_info = *static_cast<const SpotLightRenderInfo *>(infos[0].render_info);
	cmd.set_program(*spot_info.program);
	CommandBufferUtil::set_quad_vertex_state(cmd);
	cmd.set_cull_mode(VK_CULL_MODE_NONE);
	cmd.set_primitive_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);

	auto push = spot_info.push;
	push.inv_resolution = vec2(1.0f / cmd.get_viewport().width, 1.0f / cmd.get_viewport().height);
	cmd.push_constants(&push, 0, sizeof(push));

	for (unsigned i = 0; i < num_instances; )
	{
		unsigned to_render = min(256u, num_instances - i);

		auto *frag = static_cast<PositionalFragmentInfo *>(cmd.allocate_constant_data(2, 0,
		                                                                              sizeof(PositionalFragmentInfo) * to_render));
		auto *vert = static_cast<PositionalVertexInfo *>(cmd.allocate_constant_data(2, 1,
		                                                                            sizeof(PositionalVertexInfo) * to_render));

		for (unsigned j = 0; j < to_render; j++)
		{
			vert[j] = static_cast<const PositionalShaderInfo *>(infos[i + j].instance_data)->vertex;
			frag[j] = static_cast<const PositionalShaderInfo *>(infos[i + j].instance_data)->fragment;
		}

		cmd.draw(4, to_render);
		i += to_render;
	}
}

static void spot_render_common(CommandBuffer &cmd, const RenderQueueData *infos, unsigned num_instances)
{
	auto &spot_info = *static_cast<const SpotLightRenderInfo *>(infos[0].render_info);
	cmd.set_program(*spot_info.program);
	cmd.set_vertex_binding(0, *spot_info.vbo, 0, sizeof(vec3));
	cmd.set_vertex_attrib(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0);
	cmd.set_index_buffer(*spot_info.ibo, 0, VK_INDEX_TYPE_UINT16);

	auto push = spot_info.push;
	push.inv_resolution = vec2(1.0f / cmd.get_viewport().width, 1.0f / cmd.get_viewport().height);
	cmd.push_constants(&push, 0, sizeof(push));

	for (unsigned i = 0; i < num_instances; )
	{
		unsigned to_render = min(256u, num_instances - i);
		auto *frag = static_cast<PositionalFragmentInfo *>(cmd.allocate_constant_data(2, 0,
		                                                                              sizeof(PositionalFragmentInfo) * to_render));
		auto *vert = static_cast<PositionalVertexInfo *>(cmd.allocate_constant_data(2, 1,
		                                                                            sizeof(PositionalVertexInfo) * to_render));

		for (unsigned j = 0; j < to_render; j++)
		{
			vert[j] = static_cast<const PositionalShaderInfo *>(infos[i + j].instance_data)->vertex;
			frag[j] = static_cast<const PositionalShaderInfo *>(infos[i + j].instance_data)->fragment;
		}

		cmd.draw_indexed(spot_info.count, to_render);
		i += to_render;
	}
}

static void spot_render_front(CommandBuffer &cmd, const RenderQueueData *infos, unsigned num_instances)
{
	cmd.set_cull_mode(VK_CULL_MODE_BACK_BIT);
	spot_render_common(cmd, infos, num_instances);
}

static void spot_render_back(CommandBuffer &cmd, const RenderQueueData *infos, unsigned num_instances)
{
	cmd.set_cull_mode(VK_CULL_MODE_FRONT_BIT);
	cmd.set_depth_compare(VK_COMPARE_OP_GREATER);
	spot_render_common(cmd, infos, num_instances);
}

void SpotLight::get_render_info(const RenderContext &context, const CachedSpatialTransformComponent *transform,
                                RenderQueue &queue) const
{
	auto &params = context.get_render_parameters();
	auto &aabb = transform->world_aabb;
	float to_center = dot(aabb.get_center() - params.camera_position, params.camera_front);
	float radius = aabb.get_radius();
	float aabb_near = to_center - params.z_near - radius;
	float aabb_far = to_center + radius - params.z_far;

	RenderFunc func;

	if (aabb_near < 0.0f) // We risk clipping into the mesh, and since we can't rely on depthClamp, use backface.
	{
		if (aabb_far > 0.0f) // We risk clipping into far plane as well ... Use a full-screen quad.
			func = spot_render_full_screen;
		else
			func = spot_render_back;
	}
	else
		func = spot_render_front;

	Hasher h;
	auto instance_key = h.get();
	h.pointer(func);
	auto sorting_key = h.get();

	auto *spot = queue.allocate_one<PositionalShaderInfo>();
	spot->vertex.model = transform->transform->world_transform * scale(vec3(xy_range, xy_range, range));
	spot->fragment = get_shader_info(transform->transform->world_transform);

	auto *spot_info = queue.push<SpotLightRenderInfo>(Queue::Light, instance_key, sorting_key,
	                                                  func, spot);

	if (spot_info)
	{
		SpotLightRenderInfo info;

		info.count = light_mesh.spot_count;
		info.vbo = light_mesh.spot_vbo.get();
		info.ibo = light_mesh.spot_ibo.get();

		info.push.inv_view_projection = params.inv_view_projection;
		info.push.camera_pos = vec4(params.camera_position, 0.0f);

		info.program = queue.get_shader_suites()[ecast(RenderableType::SpotLight)].get_program(DrawPipeline::AlphaBlend, 0, 0,
		                                                                              func == spot_render_full_screen ? 1 : 0).get();
		*spot_info = info;
	}
}

PointLight::PointLight()
	: PositionalLight(PositionalLight::Type::Point)
{
}

void PointLight::set_range(float range)
{
	this->range = range;
	aabb = AABB(vec3(-range), vec3(range));
}

PositionalFragmentInfo PointLight::get_shader_info(const mat4 &transform) const
{
	return {
		vec4(color, 0.0f),
		vec4(constant, linear, quadratic, 1.0f / range),
		vec4(transform[3].xyz(), 0.0f),
		vec4(normalize(transform[2].xyz()), 0.0f),
	};
}

void PointLight::get_render_info(const RenderContext &context, const CachedSpatialTransformComponent *transform,
                                 RenderQueue &queue) const
{
	(void)context;
	(void)transform;
	(void)queue;
}

}<|endoftext|>


<commit_before>/*
	This file is part of the CVD Library.

	Copyright (C) 2005 The Authors

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

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

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//  videoplay.C                                                            //
//                                                                         //
//  Test program for videofilebuffer                                       //
//                                                                         //
//  Paul Smith    30 April 2004                                            //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

#include <cvd/image.h>
#include <cvd/rgb.h>
#include <cvd/byte.h>
#include <cvd/videodisplay.h>
#include <cvd/gl_helpers.h>
#include <cvd/videosource.h>

using namespace std;
using namespace CVD;

template<class C> void play(string s)
{
	VideoBuffer<C> *buffer = open_video_source<C>(s);

	VideoDisplay display(buffer->size());

	//while(buffer->frame_pending())
	for(;;)
	{
		VideoFrame<C>* frame = buffer->get_frame();
		glDrawPixels(*frame);
		buffer->put_frame(frame);
				  glFlush();
	}
}

int main(int argc, char* argv[])
{
	int type =0;

	int arg=1;

	if(argc-1 >=1)
	{
	    if(argv[arg] == string("-mono"))
		{
			arg++;
			type=1;
		}
	    else if(argv[arg] == string("-rgb8"))
		{
			arg++;
			type=2;
		}
	}

	if(arg != argc-1)
	{
		cerr << "Error: specify the video source\n";
		return 1;
	}
	try
	{
		if(type == 1)
			play<byte>(argv[arg]);
		else if(type == 2)
			play<Rgb8>(argv[arg]);
		else
			play<Rgb<byte> >(argv[arg]);
	}
	catch(CVD::Exceptions::All& e)
	{
		cout << "Error: " << e.what << endl;
	}
}
<commit_msg>double buffering.<commit_after>/*
	This file is part of the CVD Library.

	Copyright (C) 2005 The Authors

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

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

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//  videoplay.C                                                            //
//                                                                         //
//  Test program for videofilebuffer                                       //
//                                                                         //
//  Paul Smith    30 April 2004                                            //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

#include <cvd/image.h>
#include <cvd/rgb.h>
#include <cvd/byte.h>
#include <cvd/videodisplay.h>
#include <cvd/gl_helpers.h>
#include <cvd/videosource.h>

using namespace std;
using namespace CVD;

template<class C> void play(string s)
{
	VideoBuffer<C> *buffer = open_video_source<C>(s);

	VideoDisplay display(buffer->size());
	glDrawBuffer(GL_BACK);

	//while(buffer->frame_pending())
	for(;;)
	{
		VideoFrame<C>* frame = buffer->get_frame();
		glDrawPixels(*frame);
		buffer->put_frame(frame);
				  glFlush();

		display.swap_buffers();
	}
}

int main(int argc, char* argv[])
{
	int type =0;

	int arg=1;

	if(argc-1 >=1)
	{
	    if(argv[arg] == string("-mono"))
		{
			arg++;
			type=1;
		}
	    else if(argv[arg] == string("-rgb8"))
		{
			arg++;
			type=2;
		}
	}

	if(arg != argc-1)
	{
		cerr << "Error: specify the video source\n";
		return 1;
	}
	try
	{
		if(type == 1)
			play<byte>(argv[arg]);
		else if(type == 2)
			play<Rgb8>(argv[arg]);
		else
			play<Rgb<byte> >(argv[arg]);
	}
	catch(CVD::Exceptions::All& e)
	{
		cout << "Error: " << e.what << endl;
	}
}
<|endoftext|>


<commit_before>/**
 *
 */

#include <mpi.h>

int main(int argc, char** argv) {
    MPI_Init(&argc, &argv);

    MPI_Finalize();
    return 0;
}<commit_msg> + print out rank/size<commit_after>/**
 *
 */

#include <mpi.h>
#include <iostream>

int main(int argc, char** argv) {
    MPI_Init(&argc, &argv);
    int rank, size;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    std::cout << "[" << rank << "] out of 0..."
              << size - 1 << " procs\n";
    MPI_Finalize();
    return 0;
}<|endoftext|>


<commit_before>DEFINE_string(input_file_{{name}}, "{{name}}", "Input file");
Relation<{{tuple_type}}> {{resultsym}};
std::vector<std::string> schema_{{resultsym}} = { {{colnames}}  };
<commit_msg>mistake, dont print list<commit_after>DEFINE_string(input_file_{{name}}, "{{name}}", "Input file");
Relation<{{tuple_type}}> {{resultsym}};
std::vector<std::string> schema_{{resultsym}} = { {{colnames | join(',')}} };
<|endoftext|>


<commit_before>/*
 * shrenderer.cpp
 *
 * Created on: 03.07.2012
 * @author Ralph Schurade
 */
#include "shrenderer.h"
#include "shrendererthread.h"
#include "shrendererthread2.h"
#include "glfunctions.h"

#include "../../data/datasets/datasetsh.h"
#include "../../data/enums.h"
#include "../../data/models.h"
#include "../../data/vptr.h"
#include "../../algos/fmath.h"
#include "../../algos/qball.h"

#include "../../data/mesh/tesselation.h"
#include "../../data/mesh/trianglemesh2.h"

#include "../../thirdparty/newmat10/newmat.h"

#include <QGLShaderProgram>
#include <QDebug>

#include <limits>

SHRenderer::SHRenderer( std::vector<ColumnVector>* data ) :
    ObjectRenderer(),
    m_tris( 0 ),
    vboIds( new GLuint[ 3 ] ),
    m_mesh( 0 ),
    m_data( data ),
    m_scaling( 1.0 ),
    m_orient( 0 ),
    m_offset( 0 ),
    m_lod( 0 ),
    m_minMaxScaling( false ),
    m_order( 4 ),
    m_oldLoD( -1 ),
    m_pickId( GLFunctions::getPickIndex() ),
    m_masterThread( 0 ),
    m_meshUpdated( false ),
    m_updateWaiting( false )
{
}

SHRenderer::~SHRenderer()
{
    glDeleteBuffers(1, &( vboIds[ 0 ] ) );
    glDeleteBuffers(1, &( vboIds[ 1 ] ) );
    glDeleteBuffers(1, &( vboIds[ 2 ] ) );
}

void SHRenderer::init()
{
    initializeOpenGLFunctions();
    glGenBuffers( 3, vboIds );
}

void SHRenderer::draw( QMatrix4x4 p_matrix, QMatrix4x4 mv_matrix, int width, int height, int renderMode, PropertyGroup& props )
{
    float alpha = 1.0; //props.get( Fn::Property::D_ALPHA ).toFloat();
    m_renderMode = renderMode;

    m_pMatrix = p_matrix;
    m_mvMatrix = mv_matrix;

    switch ( renderMode )
    {
        case 0:
            break;
        case 1:
        {
            if ( alpha < 1.0 ) // obviously not opaque
            {
                return;
            }
            break;
        }
        default:
        {
            if ( alpha == 1.0  ) // not transparent
            {
                return;
            }
            break;
        }
    }

    setRenderParams( props );

    QGLShaderProgram* program = GLFunctions::getShader( "mesh" );

    program->bind();

    GLFunctions::setupTextures();
    GLFunctions::setTextureUniforms( GLFunctions::getShader( "mesh" ), "maingl" );
    // Set modelview-projection matrix
    program->setUniformValue( "mvp_matrix", p_matrix * mv_matrix );
    program->setUniformValue( "mv_matrixInvert", mv_matrix.inverted() );

    program->setUniformValue( "u_colorMode", 2 );
    program->setUniformValue( "u_colormap", m_colormap );
    program->setUniformValue( "u_color", m_color.redF(), m_color.greenF(), m_color.blueF(), 1.0 );
    program->setUniformValue( "u_selectedMin", m_selectedMin );
    program->setUniformValue( "u_selectedMax", m_selectedMax );
    program->setUniformValue( "u_lowerThreshold", m_lowerThreshold );
    program->setUniformValue( "u_upperThreshold", m_upperThreshold );

    float nx = props.get( Fn::Property::D_NX ).toFloat();
    float ny = props.get( Fn::Property::D_NY ).toFloat();
    float nz = props.get( Fn::Property::D_NZ ).toFloat();
    float sx = props.get( Fn::Property::G_SAGITTAL ).toFloat();
    float sy = props.get( Fn::Property::G_CORONAL ).toFloat();
    float sz = props.get( Fn::Property::G_AXIAL ).toFloat();
    float dx = props.get( Fn::Property::D_DX ).toFloat();
    float dy = props.get( Fn::Property::D_DY ).toFloat();
    float dz = props.get( Fn::Property::D_DZ ).toFloat();

    program->setUniformValue( "u_x", sx * dx + dx / 2.0f );
    program->setUniformValue( "u_y", sy * dy + dy / 2.0f );
    program->setUniformValue( "u_z", sz * dz + dz / 2.0f );
    program->setUniformValue( "u_cutLowerX", false );
    program->setUniformValue( "u_cutLowerY", false );
    program->setUniformValue( "u_cutLowerZ", false );
    program->setUniformValue( "u_cutHigherX", false );
    program->setUniformValue( "u_cutHigherY", false );
    program->setUniformValue( "u_cutHigherZ", false );

    program->setUniformValue( "u_adjustX",   0.0f );
    program->setUniformValue( "u_adjustY", 0.0f );
    program->setUniformValue( "u_adjustZ", 0.0f );

    program->setUniformValue( "u_alpha", alpha );
    program->setUniformValue( "u_renderMode", renderMode );
    program->setUniformValue( "u_canvasSize", width, height );
    program->setUniformValue( "D0", 9 );
    program->setUniformValue( "D1", 10 );
    program->setUniformValue( "D2", 11 );
    program->setUniformValue( "P0", 12 );

    program->setUniformValue( "u_lighting", props.get( Fn::Property::D_LIGHT_SWITCH ).toBool() );
    program->setUniformValue( "u_lightAmbient", props.get( Fn::Property::D_LIGHT_AMBIENT ).toFloat() );
    program->setUniformValue( "u_lightDiffuse", props.get( Fn::Property::D_LIGHT_DIFFUSE ).toFloat() );
    program->setUniformValue( "u_materialAmbient", props.get( Fn::Property::D_MATERIAL_AMBIENT ).toFloat() );
    program->setUniformValue( "u_materialDiffuse", props.get( Fn::Property::D_MATERIAL_DIFFUSE ).toFloat() );
    program->setUniformValue( "u_materialSpecular", props.get( Fn::Property::D_MATERIAL_SPECULAR ).toFloat() );
    program->setUniformValue( "u_materialShininess", props.get( Fn::Property::D_MATERIAL_SHININESS ).toFloat() );

    float pAlpha =  1.0;
    float blue = (float) ( ( m_pickId ) & 0xFF ) / 255.f;
    float green = (float) ( ( m_pickId >> 8 ) & 0xFF ) / 255.f;
    float red = (float) ( ( m_pickId >> 16 ) & 0xFF ) / 255.f;
    program->setUniformValue( "u_pickColor", red, green , blue, pAlpha );

    program->setUniformValue( "u_dims", nx * dx, ny * dy, nz * dz );

    initGeometry( props );

    if ( m_meshUpdated )
    {
        updateMesh();
    }

    if ( !m_mesh )
    {
        return;
    }

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 1 ] );
    setShaderVars( props );

    glEnable(GL_CULL_FACE);
    glCullFace( GL_BACK );
    glFrontFace( GL_CW );

    glDrawElements( GL_TRIANGLES, m_tris, GL_UNSIGNED_INT, 0 );

    glDisable(GL_CULL_FACE);

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
}

void SHRenderer::setShaderVars( PropertyGroup& props )
{
    QGLShaderProgram* program = GLFunctions::getShader( "mesh" );

    program->bind();

    intptr_t offset = 0;
    // Tell OpenGL programmable pipeline how to locate vertex position data

    int bufferSize = m_mesh->bufferSize();

    int vertexLocation = program->attributeLocation( "a_position" );
    program->enableAttributeArray( vertexLocation );
    glVertexAttribPointer( vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * bufferSize, (const void *) offset );
    offset += sizeof(float) * 3;

    int normalLocation = program->attributeLocation( "a_normal" );
    program->enableAttributeArray( normalLocation );
    glVertexAttribPointer( normalLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * bufferSize, (const void *) offset );
    offset += sizeof(float) * 3;

    int valueLocation = program->attributeLocation( "a_value" );
    program->enableAttributeArray( valueLocation );
    glVertexAttribPointer( valueLocation, 1, GL_FLOAT, GL_FALSE, sizeof(float) * bufferSize, (const void *) offset );
    offset += sizeof(float) * 1;

    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 2 ] );
    int colorLocation = program->attributeLocation( "a_color" );
    program->enableAttributeArray( colorLocation );
    glVertexAttribPointer( colorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0 );
}

void SHRenderer::initGeometry( PropertyGroup& props )
{
    float x = Models::getGlobal( Fn::Property::G_SAGITTAL ).toFloat();
    float y = Models::getGlobal( Fn::Property::G_CORONAL ).toFloat();
    float z = Models::getGlobal( Fn::Property::G_AXIAL ).toFloat();

    float zoom = Models::getGlobal( Fn::Property::G_ZOOM ).toFloat();
    float moveX = Models::getGlobal( Fn::Property::G_MOVEX ).toFloat();
    float moveY = Models::getGlobal( Fn::Property::G_MOVEY ).toFloat();

    QString s = createSettingsString( { x, y, z, m_orient, zoom, m_minMaxScaling, m_scaling, m_hideNegativeLobes, moveX, moveY, m_lod, m_offset } );
    if ( !m_updateWaiting && ( s == m_previousSettings || m_orient == 0 ) )
    {
        return;
    }
    m_previousSettings = s;

    createMesh( props );
}

void SHRenderer::setRenderParams( PropertyGroup& props )
{
    m_scaling = props.get( Fn::Property::D_SCALING ).toFloat();
    m_offset = props.get( Fn::Property::D_OFFSET ).toInt();
    m_lod = props.get( Fn::Property::D_LOD ).toInt();
    m_minMaxScaling = props.get( Fn::Property::D_MINMAX_SCALING ).toBool();
    m_hideNegativeLobes = props.get( Fn::Property::D_HIDE_NEGATIVE_LOBES ).toBool();
    m_order = props.get( Fn::Property::D_ORDER ).toInt();

    m_orient = 0;
    if ( props.get( Fn::Property::D_RENDER_AXIAL ).toBool() )
    {
        m_orient = 1;
    }
    if ( props.get( Fn::Property::D_RENDER_CORONAL ).toBool() )
    {
        m_orient += 2;
    }
    if ( props.get( Fn::Property::D_RENDER_SAGITTAL ).toBool() )
    {
        m_orient += 4;
    }

    m_colorMode = props.get( Fn::Property::D_COLORMODE ).toInt();
    m_colormap = props.get( Fn::Property::D_COLORMAP ).toInt();
    m_selectedMin = props.get( Fn::Property::D_SELECTED_MIN ).toFloat();
    m_selectedMax = props.get( Fn::Property::D_SELECTED_MAX ).toFloat();
    m_lowerThreshold = props.get( Fn::Property::D_LOWER_THRESHOLD ).toFloat();
    m_upperThreshold = props.get( Fn::Property::D_UPPER_THRESHOLD ).toFloat();
    m_color = props.get( Fn::Property::D_COLOR ).value<QColor>();
}

void SHRenderer::createMesh( PropertyGroup& props )
{
    if ( m_masterThread && m_masterThread->isRunning() )
    {
        m_updateWaiting = true;
        return;
    }

    m_updateWaiting = false;

    m_masterThread = new SHRendererThread2( 0, m_data, m_pMatrix, m_mvMatrix, props );
    connect( m_masterThread, SIGNAL( finished( TriangleMesh2* ) ), this, SLOT( slotNewMeshCreated( TriangleMesh2* ) ) );

    m_masterThread->start();
}

TriangleMesh2* SHRenderer::getMesh()
{
    return m_mesh;
}

void SHRenderer::slotNewMeshCreated( TriangleMesh2* mesh )
{
    m_newMesh = mesh;
    m_meshUpdated = true;
    Models::g()->submit();
}

void SHRenderer::updateMesh()
{
    if ( m_mesh != 0 )
    {
        delete m_mesh;

        glDeleteBuffers( 3, vboIds );
        glGenBuffers( 3, vboIds );
    }

    if ( m_newMesh )
    {
        m_mesh = m_newMesh;
        int bufferSize = m_mesh->bufferSize();

        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
        glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_mesh->numTris() * 3 * sizeof(GLuint), m_mesh->getIndexes(), GL_STATIC_DRAW );

        glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 1 ] );
        glBufferData( GL_ARRAY_BUFFER, m_mesh->numVerts() * bufferSize * sizeof(GLfloat), m_mesh->getVertices(), GL_STATIC_DRAW );

        glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 2 ] );
        glBufferData( GL_ARRAY_BUFFER, m_mesh->numVerts() * 4 * sizeof(GLfloat), m_mesh->getVertexColors(), GL_DYNAMIC_DRAW );

        m_tris = m_mesh->numTris() * 3;

        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
        glBindBuffer( GL_ARRAY_BUFFER, 0 );

        m_newMesh = 0;
    }
    m_meshUpdated = false;
}
<commit_msg>fix sh renderer for changes to mesh renderer<commit_after>/*
 * shrenderer.cpp
 *
 * Created on: 03.07.2012
 * @author Ralph Schurade
 */
#include "shrenderer.h"
#include "shrendererthread.h"
#include "shrendererthread2.h"
#include "glfunctions.h"

#include "../../data/datasets/datasetsh.h"
#include "../../data/enums.h"
#include "../../data/models.h"
#include "../../data/vptr.h"
#include "../../algos/fmath.h"
#include "../../algos/qball.h"

#include "../../data/mesh/tesselation.h"
#include "../../data/mesh/trianglemesh2.h"

#include "../../thirdparty/newmat10/newmat.h"

#include <QGLShaderProgram>
#include <QDebug>

#include <limits>

SHRenderer::SHRenderer( std::vector<ColumnVector>* data ) :
    ObjectRenderer(),
    m_tris( 0 ),
    vboIds( new GLuint[ 3 ] ),
    m_mesh( 0 ),
    m_data( data ),
    m_scaling( 1.0 ),
    m_orient( 0 ),
    m_offset( 0 ),
    m_lod( 0 ),
    m_minMaxScaling( false ),
    m_order( 4 ),
    m_oldLoD( -1 ),
    m_pickId( GLFunctions::getPickIndex() ),
    m_masterThread( 0 ),
    m_meshUpdated( false ),
    m_updateWaiting( false )
{
}

SHRenderer::~SHRenderer()
{
    glDeleteBuffers(1, &( vboIds[ 0 ] ) );
    glDeleteBuffers(1, &( vboIds[ 1 ] ) );
    glDeleteBuffers(1, &( vboIds[ 2 ] ) );
}

void SHRenderer::init()
{
    initializeOpenGLFunctions();
    glGenBuffers( 3, vboIds );
}

void SHRenderer::draw( QMatrix4x4 p_matrix, QMatrix4x4 mv_matrix, int width, int height, int renderMode, PropertyGroup& props )
{
    float alpha = 1.0; //props.get( Fn::Property::D_ALPHA ).toFloat();
    m_renderMode = renderMode;

    m_pMatrix = p_matrix;
    m_mvMatrix = mv_matrix;

    switch ( renderMode )
    {
        case 0:
            break;
        case 1:
        {
            if ( alpha < 1.0 ) // obviously not opaque
            {
                return;
            }
            break;
        }
        default:
        {
            if ( alpha == 1.0  ) // not transparent
            {
                return;
            }
            break;
        }
    }

    setRenderParams( props );

    QGLShaderProgram* program = GLFunctions::getShader( "mesh" );

    program->bind();

    GLFunctions::setupTextures();
    GLFunctions::setTextureUniforms( GLFunctions::getShader( "mesh" ), "maingl" );
    // Set modelview-projection matrix
    program->setUniformValue( "mvp_matrix", p_matrix * mv_matrix );
    program->setUniformValue( "mv_matrixInvert", mv_matrix.inverted() );

    QMatrix4x4 mat;
    program->setUniformValue( "userTransformMatrix", mat );

    program->setUniformValue( "u_colorMode", 2 );
    program->setUniformValue( "u_colormap", m_colormap );
    program->setUniformValue( "u_color", m_color.redF(), m_color.greenF(), m_color.blueF(), 1.0 );
    program->setUniformValue( "u_selectedMin", m_selectedMin );
    program->setUniformValue( "u_selectedMax", m_selectedMax );
    program->setUniformValue( "u_lowerThreshold", m_lowerThreshold );
    program->setUniformValue( "u_upperThreshold", m_upperThreshold );

    float nx = props.get( Fn::Property::D_NX ).toFloat();
    float ny = props.get( Fn::Property::D_NY ).toFloat();
    float nz = props.get( Fn::Property::D_NZ ).toFloat();
    float sx = props.get( Fn::Property::G_SAGITTAL ).toFloat();
    float sy = props.get( Fn::Property::G_CORONAL ).toFloat();
    float sz = props.get( Fn::Property::G_AXIAL ).toFloat();
    float dx = props.get( Fn::Property::D_DX ).toFloat();
    float dy = props.get( Fn::Property::D_DY ).toFloat();
    float dz = props.get( Fn::Property::D_DZ ).toFloat();

    program->setUniformValue( "u_x", sx * dx + dx / 2.0f );
    program->setUniformValue( "u_y", sy * dy + dy / 2.0f );
    program->setUniformValue( "u_z", sz * dz + dz / 2.0f );
    program->setUniformValue( "u_cutLowerX", false );
    program->setUniformValue( "u_cutLowerY", false );
    program->setUniformValue( "u_cutLowerZ", false );
    program->setUniformValue( "u_cutHigherX", false );
    program->setUniformValue( "u_cutHigherY", false );
    program->setUniformValue( "u_cutHigherZ", false );

    program->setUniformValue( "u_adjustX",   0.0f );
    program->setUniformValue( "u_adjustY", 0.0f );
    program->setUniformValue( "u_adjustZ", 0.0f );

    program->setUniformValue( "u_alpha", alpha );
    program->setUniformValue( "u_renderMode", renderMode );
    program->setUniformValue( "u_canvasSize", width, height );
    program->setUniformValue( "D0", 9 );
    program->setUniformValue( "D1", 10 );
    program->setUniformValue( "D2", 11 );
    program->setUniformValue( "P0", 12 );

    program->setUniformValue( "u_lighting", props.get( Fn::Property::D_LIGHT_SWITCH ).toBool() );
    program->setUniformValue( "u_lightAmbient", props.get( Fn::Property::D_LIGHT_AMBIENT ).toFloat() );
    program->setUniformValue( "u_lightDiffuse", props.get( Fn::Property::D_LIGHT_DIFFUSE ).toFloat() );
    program->setUniformValue( "u_materialAmbient", props.get( Fn::Property::D_MATERIAL_AMBIENT ).toFloat() );
    program->setUniformValue( "u_materialDiffuse", props.get( Fn::Property::D_MATERIAL_DIFFUSE ).toFloat() );
    program->setUniformValue( "u_materialSpecular", props.get( Fn::Property::D_MATERIAL_SPECULAR ).toFloat() );
    program->setUniformValue( "u_materialShininess", props.get( Fn::Property::D_MATERIAL_SHININESS ).toFloat() );

    float pAlpha =  1.0;
    float blue = (float) ( ( m_pickId ) & 0xFF ) / 255.f;
    float green = (float) ( ( m_pickId >> 8 ) & 0xFF ) / 255.f;
    float red = (float) ( ( m_pickId >> 16 ) & 0xFF ) / 255.f;
    program->setUniformValue( "u_pickColor", red, green , blue, pAlpha );

    program->setUniformValue( "u_dims", nx * dx, ny * dy, nz * dz );

    initGeometry( props );

    if ( m_meshUpdated )
    {
        updateMesh();
    }

    if ( !m_mesh )
    {
        return;
    }

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 1 ] );
    setShaderVars( props );

    glEnable(GL_CULL_FACE);
    glCullFace( GL_BACK );
    glFrontFace( GL_CW );

    glDrawElements( GL_TRIANGLES, m_tris, GL_UNSIGNED_INT, 0 );

    glDisable(GL_CULL_FACE);

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
}

void SHRenderer::setShaderVars( PropertyGroup& props )
{
    QGLShaderProgram* program = GLFunctions::getShader( "mesh" );

    program->bind();

    intptr_t offset = 0;
    // Tell OpenGL programmable pipeline how to locate vertex position data

    int bufferSize = m_mesh->bufferSize();

    int vertexLocation = program->attributeLocation( "a_position" );
    program->enableAttributeArray( vertexLocation );
    glVertexAttribPointer( vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * bufferSize, (const void *) offset );
    offset += sizeof(float) * 3;

    int normalLocation = program->attributeLocation( "a_normal" );
    program->enableAttributeArray( normalLocation );
    glVertexAttribPointer( normalLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * bufferSize, (const void *) offset );
    offset += sizeof(float) * 3;

    int valueLocation = program->attributeLocation( "a_value" );
    program->enableAttributeArray( valueLocation );
    glVertexAttribPointer( valueLocation, 1, GL_FLOAT, GL_FALSE, sizeof(float) * bufferSize, (const void *) offset );
    offset += sizeof(float) * 1;

    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 2 ] );
    int colorLocation = program->attributeLocation( "a_color" );
    program->enableAttributeArray( colorLocation );
    glVertexAttribPointer( colorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0 );
}

void SHRenderer::initGeometry( PropertyGroup& props )
{
    float x = Models::getGlobal( Fn::Property::G_SAGITTAL ).toFloat();
    float y = Models::getGlobal( Fn::Property::G_CORONAL ).toFloat();
    float z = Models::getGlobal( Fn::Property::G_AXIAL ).toFloat();

    float zoom = Models::getGlobal( Fn::Property::G_ZOOM ).toFloat();
    float moveX = Models::getGlobal( Fn::Property::G_MOVEX ).toFloat();
    float moveY = Models::getGlobal( Fn::Property::G_MOVEY ).toFloat();

    QString s = createSettingsString( { x, y, z, m_orient, zoom, m_minMaxScaling, m_scaling, m_hideNegativeLobes, moveX, moveY, m_lod, m_offset } );
    if ( !m_updateWaiting && ( s == m_previousSettings || m_orient == 0 ) )
    {
        return;
    }
    m_previousSettings = s;

    createMesh( props );
}

void SHRenderer::setRenderParams( PropertyGroup& props )
{
    m_scaling = props.get( Fn::Property::D_SCALING ).toFloat();
    m_offset = props.get( Fn::Property::D_OFFSET ).toInt();
    m_lod = props.get( Fn::Property::D_LOD ).toInt();
    m_minMaxScaling = props.get( Fn::Property::D_MINMAX_SCALING ).toBool();
    m_hideNegativeLobes = props.get( Fn::Property::D_HIDE_NEGATIVE_LOBES ).toBool();
    m_order = props.get( Fn::Property::D_ORDER ).toInt();

    m_orient = 0;
    if ( props.get( Fn::Property::D_RENDER_AXIAL ).toBool() )
    {
        m_orient = 1;
    }
    if ( props.get( Fn::Property::D_RENDER_CORONAL ).toBool() )
    {
        m_orient += 2;
    }
    if ( props.get( Fn::Property::D_RENDER_SAGITTAL ).toBool() )
    {
        m_orient += 4;
    }

    m_colorMode = props.get( Fn::Property::D_COLORMODE ).toInt();
    m_colormap = props.get( Fn::Property::D_COLORMAP ).toInt();
    m_selectedMin = props.get( Fn::Property::D_SELECTED_MIN ).toFloat();
    m_selectedMax = props.get( Fn::Property::D_SELECTED_MAX ).toFloat();
    m_lowerThreshold = props.get( Fn::Property::D_LOWER_THRESHOLD ).toFloat();
    m_upperThreshold = props.get( Fn::Property::D_UPPER_THRESHOLD ).toFloat();
    m_color = props.get( Fn::Property::D_COLOR ).value<QColor>();
}

void SHRenderer::createMesh( PropertyGroup& props )
{
    if ( m_masterThread && m_masterThread->isRunning() )
    {
        m_updateWaiting = true;
        return;
    }

    m_updateWaiting = false;

    m_masterThread = new SHRendererThread2( 0, m_data, m_pMatrix, m_mvMatrix, props );
    connect( m_masterThread, SIGNAL( finished( TriangleMesh2* ) ), this, SLOT( slotNewMeshCreated( TriangleMesh2* ) ) );

    m_masterThread->start();
}

TriangleMesh2* SHRenderer::getMesh()
{
    return m_mesh;
}

void SHRenderer::slotNewMeshCreated( TriangleMesh2* mesh )
{
    m_newMesh = mesh;
    m_meshUpdated = true;
    Models::g()->submit();
}

void SHRenderer::updateMesh()
{
    if ( m_mesh != 0 )
    {
        delete m_mesh;

        glDeleteBuffers( 3, vboIds );
        glGenBuffers( 3, vboIds );
    }

    if ( m_newMesh )
    {
        m_mesh = m_newMesh;
        int bufferSize = m_mesh->bufferSize();

        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
        glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_mesh->numTris() * 3 * sizeof(GLuint), m_mesh->getIndexes(), GL_STATIC_DRAW );

        glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 1 ] );
        glBufferData( GL_ARRAY_BUFFER, m_mesh->numVerts() * bufferSize * sizeof(GLfloat), m_mesh->getVertices(), GL_STATIC_DRAW );

        glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 2 ] );
        glBufferData( GL_ARRAY_BUFFER, m_mesh->numVerts() * 4 * sizeof(GLfloat), m_mesh->getVertexColors(), GL_DYNAMIC_DRAW );

        m_tris = m_mesh->numTris() * 3;

        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
        glBindBuffer( GL_ARRAY_BUFFER, 0 );

        m_newMesh = 0;
    }
    m_meshUpdated = false;
}
<|endoftext|>


<commit_before>// Copyright 2021 atframework
// Created by owent

#include <limits>

#include <detail/libatbus_error.h>

#include <atframe/atapp.h>

#include <atframe/connectors/atapp_connector_impl.h>
#include <atframe/connectors/atapp_endpoint.h>

#ifdef max
#  undef max
#endif

namespace atapp {
LIBATAPP_MACRO_API atapp_endpoint::atapp_endpoint(app &owner, construct_helper_t &)
    : closing_(false),
      owner_(&owner),
      pending_message_size_(0)
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
      ,
      pending_message_count_(0)
#endif
{
  nearest_waker_ = std::chrono::system_clock::from_time_t(0);
}

LIBATAPP_MACRO_API atapp_endpoint::ptr_t atapp_endpoint::create(app &owner) {
  construct_helper_t helper;
  ptr_t ret = std::make_shared<atapp_endpoint>(owner, helper);
  if (ret) {
    ret->watcher_ = ret;

    FWLOGINFO("create atapp endpoint {}", reinterpret_cast<const void *>(ret.get()));
  }
  return ret;
}

LIBATAPP_MACRO_API atapp_endpoint::~atapp_endpoint() {
  reset();
  FWLOGINFO("destroy atapp endpoint {}", reinterpret_cast<const void *>(this));
}

void atapp_endpoint::reset() {
  if (closing_) {
    return;
  }
  closing_ = true;

  cancel_pending_messages();

  handle_set_t handles;
  handles.swap(refer_connections_);

  for (handle_set_t::const_iterator iter = handles.begin(); iter != handles.end(); ++iter) {
    if (*iter) {
      atapp_endpoint_bind_helper::unbind(**iter, *this);
    }
  }

  closing_ = false;
}

LIBATAPP_MACRO_API void atapp_endpoint::add_connection_handle(atapp_connection_handle &handle) {
  if (closing_) {
    return;
  }

  atapp_endpoint_bind_helper::bind(handle, *this);
}

LIBATAPP_MACRO_API void atapp_endpoint::remove_connection_handle(atapp_connection_handle &handle) {
  if (closing_) {
    return;
  }

  atapp_endpoint_bind_helper::unbind(handle, *this);
}

LIBATAPP_MACRO_API atapp_connection_handle *atapp_endpoint::get_ready_connection_handle() const noexcept {
  for (handle_set_t::const_iterator iter = refer_connections_.begin(); iter != refer_connections_.end(); ++iter) {
    if (*iter && (*iter)->is_ready()) {
      return *iter;
    }
  }

  return nullptr;
}

LIBATAPP_MACRO_API uint64_t atapp_endpoint::get_id() const noexcept {
  if (!discovery_) {
    return 0;
  }

  return discovery_->get_discovery_info().id();
}

LIBATAPP_MACRO_API const std::string &atapp_endpoint::get_name() const noexcept {
  if (!discovery_) {
    static std::string empty;
    return empty;
  }

  return discovery_->get_discovery_info().name();
}

LIBATAPP_MACRO_API const etcd_discovery_node::ptr_t &atapp_endpoint::get_discovery() const noexcept {
  return discovery_;
}

LIBATAPP_MACRO_API void atapp_endpoint::update_discovery(const etcd_discovery_node::ptr_t &discovery) noexcept {
  if (discovery_ == discovery) {
    return;
  }

  discovery_ = discovery;

  if (discovery) {
    FWLOGINFO("update atapp endpoint {} with {}({})", reinterpret_cast<const void *>(this),
              discovery->get_discovery_info().id(), discovery->get_discovery_info().name());
  }
}

LIBATAPP_MACRO_API int32_t atapp_endpoint::push_forward_message(int32_t type, uint64_t &msg_sequence, const void *data,
                                                                size_t data_size,
                                                                const atapp::protocol::atapp_metadata *metadata) {
  // Closing
  if (closing_ || nullptr == owner_) {
    do {
      atapp_connection_handle *handle = get_ready_connection_handle();
      atapp_connector_impl *connector = nullptr;
      if (nullptr != handle) {
        connector = handle->get_connector();
      }

      trigger_on_receive_forward_response(connector, handle, type, msg_sequence, EN_ATBUS_ERR_CLOSING, data, data_size,
                                          metadata);
    } while (false);
    return EN_ATBUS_ERR_CLOSING;
  }

  if (nullptr == data || 0 == data_size) {
    return EN_ATBUS_ERR_SUCCESS;
  }

  // Has handle
  do {
    if (!pending_message_.empty()) {
      break;
    }

    atapp_connection_handle *handle = get_ready_connection_handle();
    if (nullptr != handle) {
      break;
    }

    atapp_connector_impl *connector = handle->get_connector();
    if (nullptr == connector) {
      break;
    }

    int32_t ret = connector->on_send_forward_request(handle, type, &msg_sequence, data, data_size, metadata);
    if (0 != ret) {
      trigger_on_receive_forward_response(connector, handle, type, msg_sequence, ret, data, data_size, metadata);
    }

    return ret;
  } while (false);

  // Failed to add to pending
  int32_t failed_error_code = 0;
  if (nullptr != owner_) {
    uint64_t send_buffer_number = owner_->get_origin_configure().bus().send_buffer_number();
    uint64_t send_buffer_size = owner_->get_origin_configure().bus().send_buffer_size();
    if (send_buffer_number > 0 &&
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
        pending_message_count_ + 1 > send_buffer_number
#else
        pending_message_.size() + 1 > send_buffer_number
#endif
    ) {
      failed_error_code = EN_ATBUS_ERR_BUFF_LIMIT;
    }

    if (send_buffer_size > 0 && pending_message_size_ + data_size > send_buffer_size) {
      failed_error_code = EN_ATBUS_ERR_BUFF_LIMIT;
    }
  }

  if (failed_error_code != 0) {
    atapp_connection_handle *handle = get_ready_connection_handle();
    atapp_connector_impl *connector = nullptr;
    if (nullptr != handle) {
      connector = handle->get_connector();
    }

    trigger_on_receive_forward_response(connector, handle, type, msg_sequence, failed_error_code, data, data_size,
                                        metadata);
    return failed_error_code;
  }

  // Success to add to pending
  pending_message_.push_back(pending_message_t());
  pending_message_t &msg = pending_message_.back();
  msg.type = type;
  msg.msg_sequence = msg_sequence;
  msg.data.resize(data_size);
  msg.expired_timepoint = owner_->get_last_tick_time();
  msg.expired_timepoint += owner_->get_configure_message_timeout();
  memcpy(&msg.data[0], data, data_size);
  if (nullptr != metadata) {
    msg.metadata.reset(new atapp::protocol::atapp_metadata());
    if (msg.metadata) {
      msg.metadata->CopyFrom(*metadata);
    }
  }

  pending_message_size_ += data_size;
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
  ++pending_message_count_;
#endif

  add_waker(msg.expired_timepoint);
  return EN_ATBUS_ERR_SUCCESS;
}

LIBATAPP_MACRO_API int32_t atapp_endpoint::retry_pending_messages(const util::time::time_utility::raw_time_t &tick_time,
                                                                  int32_t max_count) {
  // Including equal
  if (nearest_waker_ <= tick_time) {
    nearest_waker_ = std::chrono::system_clock::from_time_t(0);
  }

  int ret = 0;
  if (pending_message_.empty()) {
    return ret;
  }

  if (max_count <= 0) {
    max_count = std::numeric_limits<int32_t>::max();
  }

  atapp_connection_handle *handle = get_ready_connection_handle();
  atapp_connector_impl *connector = nullptr;
  if (nullptr != handle) {
    connector = handle->get_connector();
  }

  while (!pending_message_.empty()) {
    pending_message_t &msg = pending_message_.front();

    int res = EN_ATBUS_ERR_NODE_TIMEOUT;
    // Support to send data after reconnected
    if (max_count > 0 && nullptr != handle && nullptr != connector) {
      --max_count;
      res = connector->on_send_forward_request(handle, msg.type, &msg.msg_sequence,
                                               reinterpret_cast<const void *>(msg.data.data()), msg.data.size(),
                                               msg.metadata.get());
    } else if (msg.expired_timepoint > tick_time) {
      break;
    }

    if (0 != res) {
      trigger_on_receive_forward_response(connector, handle, msg.type, msg.msg_sequence, res,
                                          reinterpret_cast<const void *>(msg.data.data()), msg.data.size(),
                                          msg.metadata.get());
    }

    ++ret;

    if (likely(pending_message_size_ >= msg.data.size())) {
      pending_message_size_ -= msg.data.size();
    } else {
      pending_message_size_ = 0;
    }
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
    if (pending_message_count_ > 0) {
      --pending_message_count_;
    }
#endif
    pending_message_.pop_front();
  }

  if (pending_message_.empty()) {
    pending_message_size_ = 0;
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
    pending_message_count_ = 0;
#endif
  } else if (nullptr != owner_) {
    add_waker(pending_message_.front().expired_timepoint);
  }

  return ret;
}

LIBATAPP_MACRO_API void atapp_endpoint::add_waker(util::time::time_utility::raw_time_t wakeup_time) {
  if (wakeup_time < nearest_waker_ || std::chrono::system_clock::to_time_t(nearest_waker_) == 0) {
    if (nullptr != owner_) {
      if (owner_->add_endpoint_waker(wakeup_time, watcher_)) {
        nearest_waker_ = wakeup_time;
      }
    }
  }
}

void atapp_endpoint::cancel_pending_messages() {
  atapp_connection_handle *handle = get_ready_connection_handle();
  atapp_connector_impl *connector = nullptr;
  if (nullptr != handle) {
    connector = handle->get_connector();
  }

  if (nullptr == connector) {
    return;
  }

  while (!pending_message_.empty()) {
    const pending_message_t &msg = pending_message_.front();
    trigger_on_receive_forward_response(connector, handle, msg.type, msg.msg_sequence, EN_ATBUS_ERR_CLOSING,
                                        reinterpret_cast<const void *>(msg.data.data()), msg.data.size(),
                                        msg.metadata.get());

    if (likely(pending_message_size_ >= msg.data.size())) {
      pending_message_size_ -= msg.data.size();
    } else {
      pending_message_size_ = 0;
    }
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
    if (pending_message_count_ > 0) {
      --pending_message_count_;
    }
#endif
    pending_message_.pop_front();
  }

  pending_message_size_ = 0;
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
  pending_message_count_ = 0;
#endif
}

void atapp_endpoint::trigger_on_receive_forward_response(atapp_connector_impl *connector,
                                                         atapp_connection_handle *handle, int32_t type,
                                                         uint64_t sequence, int32_t error_code, const void *data,
                                                         size_t data_size,
                                                         const atapp::protocol::atapp_metadata *metadata) {
  if (nullptr != connector && nullptr != handle) {
    connector->on_receive_forward_response(handle, type, sequence, error_code, data, data_size, metadata);
    return;
  }

  atapp::app *app = get_owner();
  if (nullptr == app) {
    return;
  }

  // notify app
  app::message_t msg;
  msg.data = data;
  msg.data_size = data_size;
  msg.metadata = metadata;
  msg.msg_sequence = sequence;
  msg.type = type;

  app::message_sender_t sender;
  if (nullptr != handle) {
    sender.remote = handle->get_endpoint();
  }
  if (nullptr != sender.remote) {
    sender.id = sender.remote->get_id();
    sender.name = sender.remote->get_name();
  }

  app->trigger_event_on_forward_response(sender, msg, error_code);
}

}  // namespace atapp
<commit_msg>Fix new connector handle<commit_after>// Copyright 2021 atframework
// Created by owent

#include <limits>

#include <detail/libatbus_error.h>

#include <atframe/atapp.h>

#include <atframe/connectors/atapp_connector_impl.h>
#include <atframe/connectors/atapp_endpoint.h>

#ifdef max
#  undef max
#endif

namespace atapp {
LIBATAPP_MACRO_API atapp_endpoint::atapp_endpoint(app &owner, construct_helper_t &)
    : closing_(false),
      owner_(&owner),
      pending_message_size_(0)
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
      ,
      pending_message_count_(0)
#endif
{
  nearest_waker_ = std::chrono::system_clock::from_time_t(0);
}

LIBATAPP_MACRO_API atapp_endpoint::ptr_t atapp_endpoint::create(app &owner) {
  construct_helper_t helper;
  ptr_t ret = std::make_shared<atapp_endpoint>(owner, helper);
  if (ret) {
    ret->watcher_ = ret;

    FWLOGINFO("create atapp endpoint {}", reinterpret_cast<const void *>(ret.get()));
  }
  return ret;
}

LIBATAPP_MACRO_API atapp_endpoint::~atapp_endpoint() {
  reset();
  FWLOGINFO("destroy atapp endpoint {}", reinterpret_cast<const void *>(this));
}

void atapp_endpoint::reset() {
  if (closing_) {
    return;
  }
  closing_ = true;

  cancel_pending_messages();

  handle_set_t handles;
  handles.swap(refer_connections_);

  for (handle_set_t::const_iterator iter = handles.begin(); iter != handles.end(); ++iter) {
    if (*iter) {
      atapp_endpoint_bind_helper::unbind(**iter, *this);
    }
  }

  closing_ = false;
}

LIBATAPP_MACRO_API void atapp_endpoint::add_connection_handle(atapp_connection_handle &handle) {
  if (closing_) {
    return;
  }

  atapp_endpoint_bind_helper::bind(handle, *this);
}

LIBATAPP_MACRO_API void atapp_endpoint::remove_connection_handle(atapp_connection_handle &handle) {
  if (closing_) {
    return;
  }

  atapp_endpoint_bind_helper::unbind(handle, *this);
}

LIBATAPP_MACRO_API atapp_connection_handle *atapp_endpoint::get_ready_connection_handle() const noexcept {
  for (handle_set_t::const_iterator iter = refer_connections_.begin(); iter != refer_connections_.end(); ++iter) {
    if (*iter && (*iter)->is_ready()) {
      return *iter;
    }
  }

  return nullptr;
}

LIBATAPP_MACRO_API uint64_t atapp_endpoint::get_id() const noexcept {
  if (!discovery_) {
    return 0;
  }

  return discovery_->get_discovery_info().id();
}

LIBATAPP_MACRO_API const std::string &atapp_endpoint::get_name() const noexcept {
  if (!discovery_) {
    static std::string empty;
    return empty;
  }

  return discovery_->get_discovery_info().name();
}

LIBATAPP_MACRO_API const etcd_discovery_node::ptr_t &atapp_endpoint::get_discovery() const noexcept {
  return discovery_;
}

LIBATAPP_MACRO_API void atapp_endpoint::update_discovery(const etcd_discovery_node::ptr_t &discovery) noexcept {
  if (discovery_ == discovery) {
    return;
  }

  discovery_ = discovery;

  if (discovery) {
    FWLOGINFO("update atapp endpoint {} with {}({})", reinterpret_cast<const void *>(this),
              discovery->get_discovery_info().id(), discovery->get_discovery_info().name());
  }
}

LIBATAPP_MACRO_API int32_t atapp_endpoint::push_forward_message(int32_t type, uint64_t &msg_sequence, const void *data,
                                                                size_t data_size,
                                                                const atapp::protocol::atapp_metadata *metadata) {
  // Closing
  if (closing_ || nullptr == owner_) {
    do {
      atapp_connection_handle *handle = get_ready_connection_handle();
      atapp_connector_impl *connector = nullptr;
      if (nullptr != handle) {
        connector = handle->get_connector();
      }

      trigger_on_receive_forward_response(connector, handle, type, msg_sequence, EN_ATBUS_ERR_CLOSING, data, data_size,
                                          metadata);
    } while (false);
    return EN_ATBUS_ERR_CLOSING;
  }

  if (nullptr == data || 0 == data_size) {
    return EN_ATBUS_ERR_SUCCESS;
  }

  // Has handle
  do {
    if (!pending_message_.empty()) {
      break;
    }

    atapp_connection_handle *handle = get_ready_connection_handle();
    if (nullptr == handle) {
      break;
    }

    atapp_connector_impl *connector = handle->get_connector();
    if (nullptr == connector) {
      break;
    }

    int32_t ret = connector->on_send_forward_request(handle, type, &msg_sequence, data, data_size, metadata);
    if (0 != ret) {
      trigger_on_receive_forward_response(connector, handle, type, msg_sequence, ret, data, data_size, metadata);
    }

    return ret;
  } while (false);

  // Failed to add to pending
  int32_t failed_error_code = 0;
  if (nullptr != owner_) {
    uint64_t send_buffer_number = owner_->get_origin_configure().bus().send_buffer_number();
    uint64_t send_buffer_size = owner_->get_origin_configure().bus().send_buffer_size();
    if (send_buffer_number > 0 &&
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
        pending_message_count_ + 1 > send_buffer_number
#else
        pending_message_.size() + 1 > send_buffer_number
#endif
    ) {
      failed_error_code = EN_ATBUS_ERR_BUFF_LIMIT;
    }

    if (send_buffer_size > 0 && pending_message_size_ + data_size > send_buffer_size) {
      failed_error_code = EN_ATBUS_ERR_BUFF_LIMIT;
    }
  }

  if (failed_error_code != 0) {
    atapp_connection_handle *handle = get_ready_connection_handle();
    atapp_connector_impl *connector = nullptr;
    if (nullptr != handle) {
      connector = handle->get_connector();
    }

    trigger_on_receive_forward_response(connector, handle, type, msg_sequence, failed_error_code, data, data_size,
                                        metadata);
    return failed_error_code;
  }

  // Success to add to pending
  pending_message_.push_back(pending_message_t());
  pending_message_t &msg = pending_message_.back();
  msg.type = type;
  msg.msg_sequence = msg_sequence;
  msg.data.resize(data_size);
  msg.expired_timepoint = owner_->get_last_tick_time();
  msg.expired_timepoint += owner_->get_configure_message_timeout();
  memcpy(&msg.data[0], data, data_size);
  if (nullptr != metadata) {
    msg.metadata.reset(new atapp::protocol::atapp_metadata());
    if (msg.metadata) {
      msg.metadata->CopyFrom(*metadata);
    }
  }

  pending_message_size_ += data_size;
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
  ++pending_message_count_;
#endif

  add_waker(msg.expired_timepoint);
  return EN_ATBUS_ERR_SUCCESS;
}

LIBATAPP_MACRO_API int32_t atapp_endpoint::retry_pending_messages(const util::time::time_utility::raw_time_t &tick_time,
                                                                  int32_t max_count) {
  // Including equal
  if (nearest_waker_ <= tick_time) {
    nearest_waker_ = std::chrono::system_clock::from_time_t(0);
  }

  int ret = 0;
  if (pending_message_.empty()) {
    return ret;
  }

  if (max_count <= 0) {
    max_count = std::numeric_limits<int32_t>::max();
  }

  atapp_connection_handle *handle = get_ready_connection_handle();
  atapp_connector_impl *connector = nullptr;
  if (nullptr != handle) {
    connector = handle->get_connector();
  }

  while (!pending_message_.empty()) {
    pending_message_t &msg = pending_message_.front();

    int res = EN_ATBUS_ERR_NODE_TIMEOUT;
    // Support to send data after reconnected
    if (max_count > 0 && nullptr != handle && nullptr != connector) {
      --max_count;
      res = connector->on_send_forward_request(handle, msg.type, &msg.msg_sequence,
                                               reinterpret_cast<const void *>(msg.data.data()), msg.data.size(),
                                               msg.metadata.get());
    } else if (msg.expired_timepoint > tick_time) {
      break;
    }

    if (0 != res) {
      trigger_on_receive_forward_response(connector, handle, msg.type, msg.msg_sequence, res,
                                          reinterpret_cast<const void *>(msg.data.data()), msg.data.size(),
                                          msg.metadata.get());
    }

    ++ret;

    if (likely(pending_message_size_ >= msg.data.size())) {
      pending_message_size_ -= msg.data.size();
    } else {
      pending_message_size_ = 0;
    }
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
    if (pending_message_count_ > 0) {
      --pending_message_count_;
    }
#endif
    pending_message_.pop_front();
  }

  if (pending_message_.empty()) {
    pending_message_size_ = 0;
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
    pending_message_count_ = 0;
#endif
  } else if (nullptr != owner_) {
    add_waker(pending_message_.front().expired_timepoint);
  }

  return ret;
}

LIBATAPP_MACRO_API void atapp_endpoint::add_waker(util::time::time_utility::raw_time_t wakeup_time) {
  if (wakeup_time < nearest_waker_ || std::chrono::system_clock::to_time_t(nearest_waker_) == 0) {
    if (nullptr != owner_) {
      if (owner_->add_endpoint_waker(wakeup_time, watcher_)) {
        nearest_waker_ = wakeup_time;
      }
    }
  }
}

void atapp_endpoint::cancel_pending_messages() {
  atapp_connection_handle *handle = get_ready_connection_handle();
  atapp_connector_impl *connector = nullptr;
  if (nullptr != handle) {
    connector = handle->get_connector();
  }

  if (nullptr == connector) {
    return;
  }

  while (!pending_message_.empty()) {
    const pending_message_t &msg = pending_message_.front();
    trigger_on_receive_forward_response(connector, handle, msg.type, msg.msg_sequence, EN_ATBUS_ERR_CLOSING,
                                        reinterpret_cast<const void *>(msg.data.data()), msg.data.size(),
                                        msg.metadata.get());

    if (likely(pending_message_size_ >= msg.data.size())) {
      pending_message_size_ -= msg.data.size();
    } else {
      pending_message_size_ = 0;
    }
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
    if (pending_message_count_ > 0) {
      --pending_message_count_;
    }
#endif
    pending_message_.pop_front();
  }

  pending_message_size_ = 0;
#if defined(LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST) && LIBATAPP_ENABLE_CUSTOM_COUNT_FOR_STD_LIST
  pending_message_count_ = 0;
#endif
}

void atapp_endpoint::trigger_on_receive_forward_response(atapp_connector_impl *connector,
                                                         atapp_connection_handle *handle, int32_t type,
                                                         uint64_t sequence, int32_t error_code, const void *data,
                                                         size_t data_size,
                                                         const atapp::protocol::atapp_metadata *metadata) {
  if (nullptr != connector && nullptr != handle) {
    connector->on_receive_forward_response(handle, type, sequence, error_code, data, data_size, metadata);
    return;
  }

  atapp::app *app = get_owner();
  if (nullptr == app) {
    return;
  }

  // notify app
  app::message_t msg;
  msg.data = data;
  msg.data_size = data_size;
  msg.metadata = metadata;
  msg.msg_sequence = sequence;
  msg.type = type;

  app::message_sender_t sender;
  if (nullptr != handle) {
    sender.remote = handle->get_endpoint();
  }
  if (nullptr != sender.remote) {
    sender.id = sender.remote->get_id();
    sender.name = sender.remote->get_name();
  }

  app->trigger_event_on_forward_response(sender, msg, error_code);
}

}  // namespace atapp
<|endoftext|>