<commit_before>#include <Eigen/Geometry>
#include <ros/ros.h>
#include <tf/transform_datatypes.h>
#include <tf/transform_broadcaster.h>
#include <tf/transform_listener.h>
#include <tf/transform_broadcaster.h>
#include <tf_conversions/tf_eigen.h>
#include <geometry_msgs/QuaternionStamped.h>
#include <nav_msgs/Odometry.h>
#include <sensor_msgs/Imu.h>
#include <robot_kf/robot_kf.h>

static double const big = 99999.0;

static boost::shared_ptr<tf::TransformListener> sub_tf;
static boost::shared_ptr<tf::TransformBroadcaster> pub_tf;
static ros::Subscriber sub_compass, sub_encoders, sub_gps;
static ros::Publisher pub_fused;

static robot_kf::KalmanFilter kf;
static geometry_msgs::Twist velocity;

static bool watch_compass, watch_encoders, watch_gps;
static std::string global_frame_id, odom_frame_id, base_frame_id;

static void publish(ros::Time stamp)
{
    Eigen::Vector3d const state = kf.getState();

    // Wrap the fused state estimate in a ROS message.
    geometry_msgs::PoseStamped fused_base;
    fused_base.header.stamp    = stamp;
    fused_base.header.frame_id = base_frame_id;
    fused_base.pose.position.x = state[0];
    fused_base.pose.position.y = state[1];
    fused_base.pose.position.z = 0.0;
    fused_base.pose.orientation = tf::createQuaternionMsgFromYaw(state[2]);

    // We can't directly publish the transformation from global_frame_id to
    // base_frame_id because it would create a cycle in the TF tree. Instead,
    // we publish a transform from global_frame_id to odom_frame_id. This is
    // equivalent to transforming from base_frame_id to odom_frame_id.
    geometry_msgs::PoseStamped fused_odom;
    sub_tf->transformPose(odom_frame_id, fused_base, fused_odom);

    // Publish the odometry message.
    nav_msgs::Odometry msg;
    msg.header.stamp = stamp;
    msg.header.frame_id = global_frame_id;
    msg.child_frame_id = odom_frame_id;
    msg.pose.pose = fused_odom.pose;
    msg.pose.covariance[0] = -1;
    msg.twist.twist = velocity;
    msg.twist.covariance[0] = -1;
    pub_fused.publish(msg);

    // Transformation.
    geometry_msgs::TransformStamped transform;
    transform.header.stamp = stamp;
    transform.header.frame_id = global_frame_id;
    transform.child_frame_id = odom_frame_id;
    transform.transform.translation.x = fused_odom.pose.position.x;
    transform.transform.translation.y = fused_odom.pose.position.y;
    transform.transform.translation.z = fused_odom.pose.position.z;
    transform.transform.rotation = fused_odom.pose.orientation;
    pub_tf->sendTransform(transform);
}

static void updateCompass(sensor_msgs::Imu const &msg)
{
    ros::Time const stamp = msg.header.stamp;
    std::string const frame_id = msg.header.frame_id;

    // Transform the orientation into the base coordinate frame.
    geometry_msgs::QuaternionStamped stamped_in, stamped_out;
    stamped_in.header.frame_id = frame_id;
    stamped_in.header.stamp    = stamp;
    stamped_in.quaternion = msg.orientation;
    sub_tf->transformQuaternion(base_frame_id, stamped_in, stamped_out);

    // Rotate the covariance matrix according to the transformation.
    tf::StampedTransform transform;
    Eigen::Affine3d eigen_transform;
    sub_tf->lookupTransform(base_frame_id, frame_id, stamp, transform);
    tf::TransformTFToEigen(transform, eigen_transform);

    Eigen::Matrix3d const rotation = eigen_transform.rotation();
    Eigen::Map<Eigen::Matrix3d const> cov_raw(&msg.orientation_covariance.front());
    Eigen::Matrix3d const cov = rotation.transpose() * cov_raw * rotation;

    kf.update_compass(tf::getYaw(stamped_out.quaternion), cov(2, 2));
    if (watch_compass) publish(stamp);
}

static void updateEncoders(nav_msgs::Odometry const &msg)
{
    if (msg.header.frame_id != odom_frame_id
     || msg.child_frame_id != base_frame_id) {
        ROS_ERROR_THROTTLE(10,
            "Odometry message must have a frame_id '%s' and child_frame_id '%s'",
            odom_frame_id.c_str(), base_frame_id.c_str()
        );
        return;
    }

    Eigen::Vector3d const z = (Eigen::Vector3d() <<
        msg.pose.pose.position.x,
        msg.pose.pose.position.y,
        tf::getYaw(msg.pose.pose.orientation)
    ).finished();
    Eigen::Map<Eigen::Matrix<double, 6, 6> const> cov_raw(
        &msg.pose.covariance.front()
    );

    Eigen::Matrix3d cov_z = Eigen::Matrix3d::Zero();
    cov_z.topLeftCorner<2, 2>() = cov_raw.topLeftCorner<2, 2>();
    cov_z(2, 2) = cov_raw(5, 5);

    // Save the current velocity to republish later. This is necessary because
    // no other sensors measure velocity.
    velocity = msg.twist.twist;

    kf.update_encoders(z, cov_z);
    if (watch_encoders) publish(msg.header.stamp);
}

static void updateGps(nav_msgs::Odometry const &msg)
{
    try {
        ros::Time const stamp = msg.header.stamp;
        std::string const frame_id = msg.child_frame_id;

        // Transform the position into the base coordinate frame.
        geometry_msgs::PointStamped stamped_in, stamped_out;
        stamped_in.header.stamp = stamp;
        stamped_in.header.frame_id = frame_id;
        stamped_in.point = msg.pose.pose.position;
        sub_tf->transformPoint(base_frame_id, stamped_in, stamped_out);

        Eigen::Vector2d const z = (Eigen::Vector2d() <<
            stamped_out.point.x, stamped_out.point.y).finished();
        Eigen::Map<Eigen::Matrix<double, 6, 6> const> cov_raw(
            &msg.pose.covariance.front()
        );
        Eigen::Matrix3d const cov3_raw = cov_raw.topLeftCorner<3, 3>();

        // Rotate the covariance matrix according to the transformation.
        tf::StampedTransform transform;
        Eigen::Affine3d eigen_transform;
        sub_tf->lookupTransform(base_frame_id, frame_id, stamp, transform);
        tf::TransformTFToEigen(transform, eigen_transform);

        Eigen::Matrix3d const rotation = eigen_transform.rotation();
        Eigen::Matrix3d const cov3 = rotation.transpose() * cov3_raw * rotation;
        Eigen::Matrix2d const cov  = cov3.topLeftCorner<2, 2>();

        kf.update_gps(z, cov);
        if (watch_gps) publish(msg.header.stamp);
    } catch (tf::ExtrapolationException const &e) {
        ROS_WARN("%s", e.what());
    }
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "robot_kf_node");

    ros::NodeHandle nh, nh_node("~");
    nh_node.param<bool>("watch_compass",  watch_compass,  true);
    nh_node.param<bool>("watch_encoders", watch_encoders, true);
    nh_node.param<bool>("watch_gps",      watch_gps,      true);
    nh_node.param<std::string>("global_frame_id", global_frame_id, "/map");
    nh_node.param<std::string>("odom_frame_id",   odom_frame_id,   "/odom");
    nh_node.param<std::string>("base_frame_id",   base_frame_id,   "/base_footprint");

    sub_tf = boost::make_shared<tf::TransformListener>();
    pub_tf = boost::make_shared<tf::TransformBroadcaster>();
    //sub_compass  = nh.subscribe("compass", 1, &updateCompass);
    //sub_encoders = nh.subscribe("odom", 1, &updateEncoders);
    sub_gps      = nh.subscribe("gps", 1, &updateGps);
    pub_fused    = nh.advertise<nav_msgs::Odometry>("odom_fused", 100);

    ros::spin();
    return 0;
}
<commit_msg>added try/catch blocks<commit_after>#include <Eigen/Geometry>
#include <ros/ros.h>
#include <tf/transform_datatypes.h>
#include <tf/transform_broadcaster.h>
#include <tf/transform_listener.h>
#include <tf/transform_broadcaster.h>
#include <tf_conversions/tf_eigen.h>
#include <geometry_msgs/QuaternionStamped.h>
#include <nav_msgs/Odometry.h>
#include <sensor_msgs/Imu.h>
#include <robot_kf/robot_kf.h>

static double const big = 99999.0;

static boost::shared_ptr<tf::TransformListener> sub_tf;
static boost::shared_ptr<tf::TransformBroadcaster> pub_tf;
static ros::Subscriber sub_compass, sub_encoders, sub_gps;
static ros::Publisher pub_fused;

static robot_kf::KalmanFilter kf;
static geometry_msgs::Twist velocity;

static bool watch_compass, watch_encoders, watch_gps;
static std::string global_frame_id, odom_frame_id, base_frame_id;

static void publish(ros::Time stamp)
{
    Eigen::Vector3d const state = kf.getState();

    // Wrap the fused state estimate in a ROS message.
    geometry_msgs::PoseStamped fused_base;
    fused_base.header.stamp    = stamp;
    fused_base.header.frame_id = base_frame_id;
    fused_base.pose.position.x = state[0];
    fused_base.pose.position.y = state[1];
    fused_base.pose.position.z = 0.0;
    fused_base.pose.orientation = tf::createQuaternionMsgFromYaw(state[2]);

    // We can't directly publish the transformation from global_frame_id to
    // base_frame_id because it would create a cycle in the TF tree. Instead,
    // we publish a transform from global_frame_id to odom_frame_id. This is
    // equivalent to transforming from base_frame_id to odom_frame_id.
    geometry_msgs::PoseStamped fused_odom;
    sub_tf->transformPose(odom_frame_id, fused_base, fused_odom);

    // Publish the odometry message.
    nav_msgs::Odometry msg;
    msg.header.stamp = stamp;
    msg.header.frame_id = global_frame_id;
    msg.child_frame_id = odom_frame_id;
    msg.pose.pose = fused_odom.pose;
    msg.pose.covariance[0] = -1;
    msg.twist.twist = velocity;
    msg.twist.covariance[0] = -1;
    pub_fused.publish(msg);

    // Transformation.
    geometry_msgs::TransformStamped transform;
    transform.header.stamp = stamp;
    transform.header.frame_id = global_frame_id;
    transform.child_frame_id = odom_frame_id;
    transform.transform.translation.x = fused_odom.pose.position.x;
    transform.transform.translation.y = fused_odom.pose.position.y;
    transform.transform.translation.z = fused_odom.pose.position.z;
    transform.transform.rotation = fused_odom.pose.orientation;
    pub_tf->sendTransform(transform);
}

static void updateCompass(sensor_msgs::Imu const &msg)
{
    try {
        ros::Time const stamp = msg.header.stamp;
        std::string const frame_id = msg.header.frame_id;

        // Transform the orientation into the base coordinate frame.
        geometry_msgs::QuaternionStamped stamped_in, stamped_out;
        stamped_in.header.frame_id = frame_id;
        stamped_in.header.stamp    = stamp;
        stamped_in.quaternion = msg.orientation;
        sub_tf->transformQuaternion(base_frame_id, stamped_in, stamped_out);

        // Rotate the covariance matrix according to the transformation.
        tf::StampedTransform transform;
        Eigen::Affine3d eigen_transform;
        sub_tf->lookupTransform(base_frame_id, frame_id, stamp, transform);
        tf::TransformTFToEigen(transform, eigen_transform);

        Eigen::Matrix3d const rotation = eigen_transform.rotation();
        Eigen::Map<Eigen::Matrix3d const> cov_raw(&msg.orientation_covariance.front());
        Eigen::Matrix3d const cov = rotation.transpose() * cov_raw * rotation;

        kf.update_compass(tf::getYaw(stamped_out.quaternion), cov(2, 2));
        if (watch_compass) publish(stamp);
    } catch (tf::ExtrapolationException const &e) {
        ROS_WARN("%s", e.what());
    }
}

static void updateEncoders(nav_msgs::Odometry const &msg)
{
    if (msg.header.frame_id != odom_frame_id
     || msg.child_frame_id != base_frame_id) {
        ROS_ERROR_THROTTLE(10,
            "Odometry message must have a frame_id '%s' and child_frame_id '%s'",
            odom_frame_id.c_str(), base_frame_id.c_str()
        );
        return;
    }

    Eigen::Vector3d const z = (Eigen::Vector3d() <<
        msg.pose.pose.position.x,
        msg.pose.pose.position.y,
        tf::getYaw(msg.pose.pose.orientation)
    ).finished();
    Eigen::Map<Eigen::Matrix<double, 6, 6> const> cov_raw(
        &msg.pose.covariance.front()
    );

    Eigen::Matrix3d cov_z = Eigen::Matrix3d::Zero();
    cov_z.topLeftCorner<2, 2>() = cov_raw.topLeftCorner<2, 2>();
    cov_z(2, 2) = cov_raw(5, 5);

    // Save the current velocity to republish later. This is necessary because
    // no other sensors measure velocity.
    velocity = msg.twist.twist;

    kf.update_encoders(z, cov_z);
    if (watch_encoders) publish(msg.header.stamp);
}

static void updateGps(nav_msgs::Odometry const &msg)
{
    try {
        ros::Time const stamp = msg.header.stamp;
        std::string const frame_id = msg.child_frame_id;

        // Transform the position into the base coordinate frame.
        geometry_msgs::PointStamped stamped_in, stamped_out;
        stamped_in.header.stamp = stamp;
        stamped_in.header.frame_id = frame_id;
        stamped_in.point = msg.pose.pose.position;
        sub_tf->transformPoint(base_frame_id, stamped_in, stamped_out);

        Eigen::Vector2d const z = (Eigen::Vector2d() <<
            stamped_out.point.x, stamped_out.point.y).finished();
        Eigen::Map<Eigen::Matrix<double, 6, 6> const> cov_raw(
            &msg.pose.covariance.front()
        );
        Eigen::Matrix3d const cov3_raw = cov_raw.topLeftCorner<3, 3>();

        // Rotate the covariance matrix according to the transformation.
        tf::StampedTransform transform;
        Eigen::Affine3d eigen_transform;
        sub_tf->lookupTransform(base_frame_id, frame_id, stamp, transform);
        tf::TransformTFToEigen(transform, eigen_transform);

        Eigen::Matrix3d const rotation = eigen_transform.rotation();
        Eigen::Matrix3d const cov3 = rotation.transpose() * cov3_raw * rotation;
        Eigen::Matrix2d const cov  = cov3.topLeftCorner<2, 2>();

        kf.update_gps(z, cov);
        if (watch_gps) publish(msg.header.stamp);
    } catch (tf::ExtrapolationException const &e) {
        ROS_WARN("%s", e.what());
    }
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "robot_kf_node");

    ros::NodeHandle nh, nh_node("~");
    nh_node.param<bool>("watch_compass",  watch_compass,  true);
    nh_node.param<bool>("watch_encoders", watch_encoders, true);
    nh_node.param<bool>("watch_gps",      watch_gps,      true);
    nh_node.param<std::string>("global_frame_id", global_frame_id, "/map");
    nh_node.param<std::string>("odom_frame_id",   odom_frame_id,   "/odom");
    nh_node.param<std::string>("base_frame_id",   base_frame_id,   "/base_footprint");

    sub_tf = boost::make_shared<tf::TransformListener>();
    pub_tf = boost::make_shared<tf::TransformBroadcaster>();
    sub_compass  = nh.subscribe("compass", 1, &updateCompass);
    //sub_encoders = nh.subscribe("odom", 1, &updateEncoders);
    sub_gps      = nh.subscribe("gps", 1, &updateGps);
    pub_fused    = nh.advertise<nav_msgs::Odometry>("odom_fused", 100);

    ros::spin();
    return 0;
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2012 Heiko Strathmann
 */

#include <shogun/statistics/TwoSampleTestStatistic.h>
#include <shogun/features/Features.h>

using namespace shogun;

CTwoSampleTestStatistic::CTwoSampleTestStatistic() : CTestStatistic()
{
	init();
}

CTwoSampleTestStatistic::CTwoSampleTestStatistic(CFeatures* p_and_q,
		index_t q_start) :
		CTestStatistic()
{
	init();

	m_p_and_q=p_and_q;
	SG_REF(m_p_and_q);

	m_q_start=q_start;
}

CTwoSampleTestStatistic::~CTwoSampleTestStatistic()
{
	SG_UNREF(m_p_and_q);
}

void CTwoSampleTestStatistic::init()
{
	/* TODO register parameters */
	m_p_and_q=NULL;
	m_q_start=0;
	m_bootstrap_iterations=100;
	m_p_value_method=BOOTSTRAP;
}

void CTwoSampleTestStatistic::set_p_value_method(EPValueMethod p_value_method)
{
	m_p_value_method=p_value_method;
}

SGVector<float64_t> CTwoSampleTestStatistic::bootstrap_null()
{
	/* compute bootstrap statistics for null distribution */
	SGVector<float64_t> results(m_bootstrap_iterations);

	/* memory for index permutations, (would slow down loop) */
	SGVector<index_t> ind_permutation(m_p_and_q->get_num_vectors());
	ind_permutation.range_fill();

	for (index_t i=0; i<m_bootstrap_iterations; ++i)
	{
		/* idea: merge features of p and q, shuffle, and compute statistic.
		 * This is done using subsets here */

		/* create index permutation and add as subset. This will mix samples
		 * from p and q */
		SGVector<int32_t>::permute_vector(ind_permutation);
		m_p_and_q->add_subset(ind_permutation);

		/* compute statistic for this permutation of mixed samples */
		results.vector[i]=compute_statistic();

		/* clean up */
		m_p_and_q->remove_subset();
	}

	/* clean up and return */
	return results;
}

void CTwoSampleTestStatistic::set_bootstrap_iterations(index_t bootstrap_iterations)
{
	m_bootstrap_iterations=bootstrap_iterations;
}

float64_t CTwoSampleTestStatistic::compute_p_value(float64_t statistic)
{
	float64_t result=0;

	if (m_p_value_method==BOOTSTRAP)
	{
		/* bootstrap a bunch of MMD values from null distribution */
		SGVector<float64_t> values=bootstrap_null();

		/* find out percentile of parameter "statistic" in null distribution */
		CMath::qsort(values);
		float64_t i=CMath::find_position_to_insert(values, statistic);

		/* return corresponding p-value */
		result=1.0-i/values.vlen;
	}
	else
	{
		SG_ERROR("%s::compute_p_value(): Unknown method to compute"
				" p-value!\n");
	}

	return result;
}

<commit_msg>moved some code outside loop to gain performance<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2012 Heiko Strathmann
 */

#include <shogun/statistics/TwoSampleTestStatistic.h>
#include <shogun/features/Features.h>

using namespace shogun;

CTwoSampleTestStatistic::CTwoSampleTestStatistic() : CTestStatistic()
{
	init();
}

CTwoSampleTestStatistic::CTwoSampleTestStatistic(CFeatures* p_and_q,
		index_t q_start) :
		CTestStatistic()
{
	init();

	m_p_and_q=p_and_q;
	SG_REF(m_p_and_q);

	m_q_start=q_start;
}

CTwoSampleTestStatistic::~CTwoSampleTestStatistic()
{
	SG_UNREF(m_p_and_q);
}

void CTwoSampleTestStatistic::init()
{
	/* TODO register parameters */
	m_p_and_q=NULL;
	m_q_start=0;
	m_bootstrap_iterations=100;
	m_p_value_method=BOOTSTRAP;
}

void CTwoSampleTestStatistic::set_p_value_method(EPValueMethod p_value_method)
{
	m_p_value_method=p_value_method;
}

SGVector<float64_t> CTwoSampleTestStatistic::bootstrap_null()
{
	/* compute bootstrap statistics for null distribution */
	SGVector<float64_t> results(m_bootstrap_iterations);

	/* memory for index permutations, (would slow down loop) */
	SGVector<index_t> ind_permutation(m_p_and_q->get_num_vectors());
	ind_permutation.range_fill();
	m_p_and_q->add_subset(ind_permutation);

	for (index_t i=0; i<m_bootstrap_iterations; ++i)
	{
		/* idea: merge features of p and q, shuffle, and compute statistic.
		 * This is done using subsets here */

		/* create index permutation and add as subset. This will mix samples
		 * from p and q */
		SGVector<int32_t>::permute_vector(ind_permutation);

		/* compute statistic for this permutation of mixed samples */
		results.vector[i]=compute_statistic();
	}

	/* clean up */
	m_p_and_q->remove_subset();

	/* clean up and return */
	return results;
}

void CTwoSampleTestStatistic::set_bootstrap_iterations(index_t bootstrap_iterations)
{
	m_bootstrap_iterations=bootstrap_iterations;
}

float64_t CTwoSampleTestStatistic::compute_p_value(float64_t statistic)
{
	float64_t result=0;

	if (m_p_value_method==BOOTSTRAP)
	{
		/* bootstrap a bunch of MMD values from null distribution */
		SGVector<float64_t> values=bootstrap_null();

		/* find out percentile of parameter "statistic" in null distribution */
		CMath::qsort(values);
		float64_t i=CMath::find_position_to_insert(values, statistic);

		/* return corresponding p-value */
		result=1.0-i/values.vlen;
	}
	else
	{
		SG_ERROR("%s::compute_p_value(): Unknown method to compute"
				" p-value!\n");
	}

	return result;
}

<|endoftext|>


<commit_before>#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

#include <boost/filesystem.hpp>

#include <math.h>

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include "test.h"

#include "narf/camera.h"
#include "narf/entity.h"
#include "narf/input.h"
#include "narf/vector.h"
#include "narf/world.h"
#include "narf/config/config.h"

#include "narf/gl/gl.h"

// TODO: this is all hacky test code - refactor into nicely modularized code

narf::Entity *player;
narf::Entity *bouncy_block; // temp hack

narf::config::ConfigManager configmanager;

narf::Camera cam;

const float movespeed = 25.0f;

narf::World *world;

#define WORLD_X_MAX 64
#define WORLD_Y_MAX 64
#define WORLD_Z_MAX 64

SDL_Surface *tiles_surf;

narf::gl::Context *display;
narf::gl::Texture *tiles_tex;

boost::filesystem::path data_dir;

float clampf(float val, float min, float max)
{
	if (val < min) val = min;
	if (val > max) val = max;
	return val;
}

bool init_video(int w, int h, int bpp, bool fullscreen)
{
	display = new narf::gl::Context();
	if (!display->set_display_mode(w, h, bpp, fullscreen)) {
		return false;
	}

	// viewer projection
	glMatrixMode(GL_PROJECTION);
	//float fovx = 90.0f; // degrees
	float fovy = 60.0f; // degrees
	float aspect = (float)w / (float)h ; // TODO: include fovx in calculation
	gluPerspective(fovy, aspect, 0.1, 1000.0f);
	glMatrixMode(GL_MODELVIEW);

	glEnable(GL_DEPTH_TEST);

	glEnable(GL_TEXTURE_2D);

	// for drawing outlines
	glPolygonOffset(1.0, 2);
	glEnable(GL_POLYGON_OFFSET_FILL);

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);

	return true;
}

bool init_textures()
{
	const std::string terrain_file = configmanager.get<std::string>("test.terrain");
	tiles_surf = IMG_Load((data_dir / terrain_file).string().c_str());
	if (!tiles_surf) {
		fprintf(stderr, "%s not found!\n", terrain_file.c_str());
		SDL_Quit();
	}

	tiles_tex = new narf::gl::Texture(display);
	if (!tiles_tex->upload(tiles_surf)) {
		assert(0);
		return false;
	}

	return true;
}

void draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	world->render(tiles_tex, &cam);

	// temp hack: draw an entity as a cube for physics demo
	void draw_cube(float x, float y, float z, uint8_t type, unsigned draw_face_mask);
	draw_cube(bouncy_block->position.x, bouncy_block->position.y, bouncy_block->position.z, 1, 0xFF);

	SDL_GL_SwapBuffers();
}

void poll_input(narf::Input *input)
{
	SDL_Event e;

	input->begin_sample();
	while (SDL_PollEvent(&e)) {
		input->process_event(&e);
	}
	input->end_sample();
}

void sim_frame(const narf::Input &input, double t, double dt)
{
	// TODO: decouple player direction and camera direction
	cam.yaw += input.look_rel().x;
	cam.yaw = fmodf(cam.yaw, (float)M_PI * 2.0f);

	cam.pitch += input.look_rel().y;
	cam.pitch = clampf(cam.pitch, -(float)M_PI / 2, (float)M_PI / 2);

	narf::Vector3f vel_rel(0.0f, 0.0f, 0.0f);

	if (input.move_forward()) {
		vel_rel -= narf::Vector3f(cosf(cam.yaw + (float)M_PI / 2), 0.0f, sinf(cam.yaw + (float)M_PI / 2));
	} else if (input.move_backward()) {
		vel_rel += narf::Vector3f(cosf(cam.yaw + (float)M_PI / 2), 0.0f, sinf(cam.yaw + (float)M_PI / 2));
	}

	if (input.strafe_left()) {
		vel_rel -= narf::Vector3f(cosf(cam.yaw), 0.0f, sinf(cam.yaw));
	} else if (input.strafe_right()) {
		vel_rel += narf::Vector3f(cosf(cam.yaw), 0.0f, sinf(cam.yaw));
	}

	// normalize so that diagonal movement is not faster than cardinal directions
	vel_rel = vel_rel.normalize() * movespeed;

	if (input.jump()) {
		vel_rel += narf::Vector3f(0.0f, 8.0f, 0.0f);
	}

	// hax
	player->velocity.x = vel_rel.x;
	player->velocity.y += vel_rel.y;
	player->velocity.z = vel_rel.z;

	player->update(t, dt);

	// lock camera to player
	cam.position = player->position;
	cam.position.y += 2.0f;

	bouncy_block->update(t, dt);
}

double get_time()
{
	return (double)SDL_GetTicks() * 0.001; // SDL tick is a millisecond; convert to seconds
}

void game_loop()
{
	const double input_divider = configmanager.get<double>("test.input_divider");
	narf::Input input(1.0f / input_divider, 1.0f / input_divider);
	double t = 0.0;
	double t1 = get_time();
	const double physics_tick_step = configmanager.get<double>("test.physics_tick_step"); // fixed time step
	const double max_frame_time = configmanager.get<double>("test.max_frame_time");

	double t_accum = 0.0;

	double fps_t1 = get_time();
	unsigned physics_steps = 0;
	unsigned draws = 0;

	while (1) {
		double t2 = get_time();
		double frame_time = t2 - t1;

		if (frame_time > max_frame_time) {
			frame_time = max_frame_time;
		}

		t1 = t2;

		t_accum += frame_time;

		while (t_accum >= physics_tick_step)
		{
			poll_input(&input);
			if (input.exit()) {
				return;
			}
			sim_frame(input, t, physics_tick_step);
			physics_steps++;

			t_accum -= physics_tick_step;
			t += physics_tick_step;
		}

		double fps_dt = get_time() - fps_t1;
		if (fps_dt >= 1.0) {
			// update fps counter
			printf("%f physics steps/%f renders per second (dt %f)\n", (double)physics_steps / fps_dt, (double)draws / fps_dt, fps_dt);
			fps_t1 = get_time();
			draws = physics_steps = 0;
		}

		draw();
		draws++;
	}
}

float randf(float min, float max)
{
	return ((float)rand() / (float)RAND_MAX) * (max - min + 1.0f) + min;
}

int randi(int min, int max)
{
	return (int)randf(min, max); // HAX
}

void gen_world()
{
	world = new narf::World(WORLD_X_MAX, WORLD_Y_MAX, WORLD_Z_MAX, 16, 16, 16);

	// first fill a plane at y = 0
	for (int z = 0; z < WORLD_Z_MAX; z++) {
		for (int x = 0; x < WORLD_X_MAX; x++) {
			narf::Block b;
			b.id = 2; // grass
			world->put_block(&b, x, 0, z);
		}
	}

	// generate some random blocks above the ground
	for (int i = 0; i < 1000; i++) {
		int x = randi(0, WORLD_X_MAX - 1);
		int y = randi(1, 10);
		int z = randi(0, WORLD_Z_MAX - 1);
		narf::Block b;
		b.id = randi(1, 3);
		world->put_block(&b, x, y, z);
	}

	for (int i = 0; i < 10; i++) {
		narf::Block b;
		b.id = 16;
		world->put_block(&b, 5 + i, 1, 5);
		world->put_block(&b, 5, 1, 5 + i);
		world->put_block(&b, 5 + i, 1, 15);
	}

	world->set_gravity(-9.8f);
}

extern "C" int main(int argc, char **argv)
{
	printf("Version: %d.%d%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE);

	data_dir = boost::filesystem::current_path();

	// walk up the path until data directory is found
	for (auto dir = boost::filesystem::current_path(); dir != dir.root_path(); dir = dir.parent_path()) {
		data_dir = dir / "data";
		if (boost::filesystem::is_directory(data_dir)) {
			printf("Found data directory: %s\n", data_dir.string().c_str());
			break;
		}
	}

	// Will explode if things don't exist
	configmanager.load("test", (data_dir / "test.yaml").string());
	narf::config::Property bar = configmanager.get("test.foo.bar");
	printf("ConfigManager test: test.foo.bar = %d\n", bar.as<int>());

	if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
		printf("SDL_Init(SDL_INIT_EVERYTHING) failed: %s\n", SDL_GetError());
		SDL_Quit();
		return 1;
	}

	const SDL_VideoInfo *vid_info = SDL_GetVideoInfo();

	printf("Current video mode is %dx%dx%d\n", vid_info->current_w, vid_info->current_h, vid_info->vfmt->BitsPerPixel);

	int w = vid_info->current_w;
	int h = vid_info->current_h;
	int bpp = vid_info->vfmt->BitsPerPixel;
	bool fullscreen = true;

	// TODO: read w, h, bpp from config file to override defaults

	SDL_WM_SetCaption("NarfBlock", "NarfBlock");

	if (!init_video(w, h, bpp, fullscreen)) {
		fprintf(stderr, "Error: could not set OpenGL video mode %dx%d@%d bpp\n", w, h, bpp);
		SDL_Quit();
		return 1;
	}

	srand(0x1234);
	gen_world();

	player = new narf::Entity(world);

	// initial player position
	player->position = narf::Vector3f(15.0f, 1.0f, 10.0f);

	// initialize camera to look at origin
	cam.yaw = atan2f(cam.position.z, cam.position.x) - (float)M_PI / 2;
	cam.pitch = 0.0f;

	bouncy_block = new narf::Entity(world);
	bouncy_block->position = narf::Vector3f(10.0f, 5.0f, 10.0f);
	bouncy_block->bouncy = true;

	init_textures();

	SDL_ShowCursor(0);
	SDL_WM_GrabInput(SDL_GRAB_ON);

	game_loop();

	SDL_Quit();
	return 0;
}
<commit_msg>Reverting silly change to test.cpp<commit_after>#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

#include <boost/filesystem.hpp>

#include <math.h>

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include "test.h"

#include "narf/camera.h"
#include "narf/entity.h"
#include "narf/input.h"
#include "narf/vector.h"
#include "narf/world.h"
#include "narf/config/config.h"

#include "narf/gl/gl.h"

// TODO: this is all hacky test code - refactor into nicely modularized code

narf::Entity *player;
narf::Entity *bouncy_block; // temp hack

narf::config::ConfigManager configmanager;

narf::Camera cam;

const float movespeed = 25.0f;

narf::World *world;

#define WORLD_X_MAX 64
#define WORLD_Y_MAX 64
#define WORLD_Z_MAX 64

SDL_Surface *tiles_surf;

narf::gl::Context *display;
narf::gl::Texture *tiles_tex;

boost::filesystem::path data_dir;

float clampf(float val, float min, float max)
{
	if (val < min) val = min;
	if (val > max) val = max;
	return val;
}

bool init_video(int w, int h, int bpp, bool fullscreen)
{
	display = new narf::gl::Context();
	if (!display->set_display_mode(w, h, bpp, fullscreen)) {
		return false;
	}

	// viewer projection
	glMatrixMode(GL_PROJECTION);
	//float fovx = 90.0f; // degrees
	float fovy = 60.0f; // degrees
	float aspect = (float)w / (float)h ; // TODO: include fovx in calculation
	gluPerspective(fovy, aspect, 0.1, 1000.0f);
	glMatrixMode(GL_MODELVIEW);

	glEnable(GL_DEPTH_TEST);

	glEnable(GL_TEXTURE_2D);

	// for drawing outlines
	glPolygonOffset(1.0, 2);
	glEnable(GL_POLYGON_OFFSET_FILL);

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);

	return true;
}

bool init_textures()
{
	const std::string terrain_file = configmanager.get<std::string>("test.terrain");
	tiles_surf = IMG_Load((data_dir / terrain_file).string().c_str());
	if (!tiles_surf) {
		fprintf(stderr, "%s not found!\n", terrain_file.c_str());
		SDL_Quit();
	}

	tiles_tex = new narf::gl::Texture(display);
	if (!tiles_tex->upload(tiles_surf)) {
		assert(0);
		return false;
	}

	return true;
}

void draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	world->render(tiles_tex, &cam);

	// temp hack: draw an entity as a cube for physics demo
	void draw_cube(float x, float y, float z, uint8_t type, unsigned draw_face_mask);
	draw_cube(bouncy_block->position.x, bouncy_block->position.y, bouncy_block->position.z, 1, 0xFF);

	SDL_GL_SwapBuffers();
}

void poll_input(narf::Input *input)
{
	SDL_Event e;

	input->begin_sample();
	while (SDL_PollEvent(&e)) {
		input->process_event(&e);
	}
	input->end_sample();
}

void sim_frame(const narf::Input &input, double t, double dt)
{
	// TODO: decouple player direction and camera direction
	cam.yaw += input.look_rel().x;
	cam.yaw = fmodf(cam.yaw, (float)M_PI * 2.0f);

	cam.pitch += input.look_rel().y;
	cam.pitch = clampf(cam.pitch, -(float)M_PI / 2, (float)M_PI / 2);

	narf::Vector3f vel_rel(0.0f, 0.0f, 0.0f);

	if (input.move_forward()) {
		vel_rel -= narf::Vector3f(cosf(cam.yaw + (float)M_PI / 2), 0.0f, sinf(cam.yaw + (float)M_PI / 2));
	} else if (input.move_backward()) {
		vel_rel += narf::Vector3f(cosf(cam.yaw + (float)M_PI / 2), 0.0f, sinf(cam.yaw + (float)M_PI / 2));
	}

	if (input.strafe_left()) {
		vel_rel -= narf::Vector3f(cosf(cam.yaw), 0.0f, sinf(cam.yaw));
	} else if (input.strafe_right()) {
		vel_rel += narf::Vector3f(cosf(cam.yaw), 0.0f, sinf(cam.yaw));
	}

	// normalize so that diagonal movement is not faster than cardinal directions
	vel_rel = vel_rel.normalize() * movespeed;

	if (input.jump()) {
		vel_rel += narf::Vector3f(0.0f, 8.0f, 0.0f);
	}

	// hax
	player->velocity.x = vel_rel.x;
	player->velocity.y += vel_rel.y;
	player->velocity.z = vel_rel.z;

	player->update(t, dt);

	// lock camera to player
	cam.position = player->position;
	cam.position.y += 2.0f;

	bouncy_block->update(t, dt);
}

double get_time()
{
	return (double)SDL_GetTicks() * 0.001; // SDL tick is a millisecond; convert to seconds
}

void game_loop()
{
	const double input_divider = configmanager.get<double>("test.input_divider");
	narf::Input input(1.0f / input_divider, 1.0f / input_divider);
	double t = 0.0;
	double t1 = get_time();
	const double physics_rate = configmanager.get<double>("test.physics_rate");
	const double physics_tick_step = 1.0 / physics_rate; // fixed time step
	const double max_frame_time = configmanager.get<double>("test.max_frame_time");

	double t_accum = 0.0;

	double fps_t1 = get_time();
	unsigned physics_steps = 0;
	unsigned draws = 0;

	while (1) {
		double t2 = get_time();
		double frame_time = t2 - t1;

		if (frame_time > max_frame_time) {
			frame_time = max_frame_time;
		}

		t1 = t2;

		t_accum += frame_time;

		while (t_accum >= physics_tick_step)
		{
			poll_input(&input);
			if (input.exit()) {
				return;
			}
			sim_frame(input, t, physics_tick_step);
			physics_steps++;

			t_accum -= physics_tick_step;
			t += physics_tick_step;
		}

		double fps_dt = get_time() - fps_t1;
		if (fps_dt >= 1.0) {
			// update fps counter
			printf("%f physics steps/%f renders per second (dt %f)\n", (double)physics_steps / fps_dt, (double)draws / fps_dt, fps_dt);
			fps_t1 = get_time();
			draws = physics_steps = 0;
		}

		draw();
		draws++;
	}
}

float randf(float min, float max)
{
	return ((float)rand() / (float)RAND_MAX) * (max - min + 1.0f) + min;
}

int randi(int min, int max)
{
	return (int)randf(min, max); // HAX
}

void gen_world()
{
	world = new narf::World(WORLD_X_MAX, WORLD_Y_MAX, WORLD_Z_MAX, 16, 16, 16);

	// first fill a plane at y = 0
	for (int z = 0; z < WORLD_Z_MAX; z++) {
		for (int x = 0; x < WORLD_X_MAX; x++) {
			narf::Block b;
			b.id = 2; // grass
			world->put_block(&b, x, 0, z);
		}
	}

	// generate some random blocks above the ground
	for (int i = 0; i < 1000; i++) {
		int x = randi(0, WORLD_X_MAX - 1);
		int y = randi(1, 10);
		int z = randi(0, WORLD_Z_MAX - 1);
		narf::Block b;
		b.id = randi(1, 3);
		world->put_block(&b, x, y, z);
	}

	for (int i = 0; i < 10; i++) {
		narf::Block b;
		b.id = 16;
		world->put_block(&b, 5 + i, 1, 5);
		world->put_block(&b, 5, 1, 5 + i);
		world->put_block(&b, 5 + i, 1, 15);
	}

	world->set_gravity(-9.8f);
}

extern "C" int main(int argc, char **argv)
{
	printf("Version: %d.%d%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE);

	data_dir = boost::filesystem::current_path();

	// walk up the path until data directory is found
	for (auto dir = boost::filesystem::current_path(); dir != dir.root_path(); dir = dir.parent_path()) {
		data_dir = dir / "data";
		if (boost::filesystem::is_directory(data_dir)) {
			printf("Found data directory: %s\n", data_dir.string().c_str());
			break;
		}
	}

	// Will explode if things don't exist
	configmanager.load("test", (data_dir / "test.yaml").string());
	narf::config::Property bar = configmanager.get("test.foo.bar");
	printf("ConfigManager test: test.foo.bar = %d\n", bar.as<int>());

	if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
		printf("SDL_Init(SDL_INIT_EVERYTHING) failed: %s\n", SDL_GetError());
		SDL_Quit();
		return 1;
	}

	const SDL_VideoInfo *vid_info = SDL_GetVideoInfo();

	printf("Current video mode is %dx%dx%d\n", vid_info->current_w, vid_info->current_h, vid_info->vfmt->BitsPerPixel);

	int w = vid_info->current_w;
	int h = vid_info->current_h;
	int bpp = vid_info->vfmt->BitsPerPixel;
	bool fullscreen = true;

	// TODO: read w, h, bpp from config file to override defaults

	SDL_WM_SetCaption("NarfBlock", "NarfBlock");

	if (!init_video(w, h, bpp, fullscreen)) {
		fprintf(stderr, "Error: could not set OpenGL video mode %dx%d@%d bpp\n", w, h, bpp);
		SDL_Quit();
		return 1;
	}

	srand(0x1234);
	gen_world();

	player = new narf::Entity(world);

	// initial player position
	player->position = narf::Vector3f(15.0f, 1.0f, 10.0f);

	// initialize camera to look at origin
	cam.yaw = atan2f(cam.position.z, cam.position.x) - (float)M_PI / 2;
	cam.pitch = 0.0f;

	bouncy_block = new narf::Entity(world);
	bouncy_block->position = narf::Vector3f(10.0f, 5.0f, 10.0f);
	bouncy_block->bouncy = true;

	init_textures();

	SDL_ShowCursor(0);
	SDL_WM_GrabInput(SDL_GRAB_ON);

	game_loop();

	SDL_Quit();
	return 0;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2009, Arvid Norberg
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 the author 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.

*/

#include <ctime>
#include <string>
#include <cstdio>
#include <boost/limits.hpp>
#include <boost/version.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/time.hpp"

#ifndef _WIN32
#include <unistd.h>
#endif

namespace libtorrent
{
	namespace aux
	{
		// used to cache the current time
		// every 100 ms. This is cheaper
		// than a system call and can be
		// used where more accurate time
		// is not necessary
		ptime g_current_time;
	}

	ptime const& TORRENT_EXPORT time_now() { return aux::g_current_time; }

	char const* time_now_string()
	{
//		time_t t = std::time(0);
//		tm* timeinfo = std::localtime(&t);
//		static char str[200];
//		std::strftime(str, 200, "%b %d %X", timeinfo);
//		return str;

		static const ptime start = time_now_hires();
		static char ret[200];
		int t = total_milliseconds(time_now_hires() - start);
		int h = t / 1000 / 60 / 60;
		t -= h * 60 * 60 * 1000;
		int m = t / 1000 / 60;
		t -= m * 60 * 1000;
		int s = t / 1000;
		t -= s * 1000;
		int ms = t;
		snprintf(ret, sizeof(ret), "%02d:%02d:%02d.%03d", h, m, s, ms);
		return ret;
	}

	std::string log_time()
	{
		static const ptime start = time_now_hires();
		char ret[200];
		snprintf(ret, sizeof(ret), "%"PRId64, total_microseconds(time_now_hires() - start));
		return ret;
	}
}

#if defined TORRENT_USE_BOOST_DATE_TIME

#include <boost/date_time/microsec_time_clock.hpp>

namespace libtorrent
{
	ptime time_now_hires()
	{ return boost::date_time::microsec_clock<ptime>::universal_time(); }
	ptime min_time()
	{ return boost::posix_time::ptime(boost::posix_time::min_date_time); }
	ptime max_time()
	{ return boost::posix_time::ptime(boost::posix_time::max_date_time); }
	time_duration seconds(int s) { return boost::posix_time::seconds(s); }
	time_duration milliseconds(int s) { return boost::posix_time::milliseconds(s); }
	time_duration microsec(int s) { return boost::posix_time::microsec(s); }
	time_duration minutes(int s) { return boost::posix_time::minutes(s); }
	time_duration hours(int s) { return boost::posix_time::hours(s); }

	int total_seconds(time_duration td)
	{ return td.total_seconds(); }
	int total_milliseconds(time_duration td)
	{ return td.total_milliseconds(); }
	boost::int64_t total_microseconds(time_duration td)
	{ return td.total_microseconds(); }
}

#else // TORRENT_USE_BOOST_DATE_TIME

namespace libtorrent
{
	ptime min_time() { return ptime(0); }
	ptime max_time() { return ptime((std::numeric_limits<boost::uint64_t>::max)()); }
}

#if defined TORRENT_USE_ABSOLUTE_TIME

#include <mach/mach_time.h>
#include <boost/cstdint.hpp>
#include "libtorrent/assert.hpp"

// high precision timer for darwin intel and ppc

namespace libtorrent
{
	ptime time_now_hires()
	{
		static mach_timebase_info_data_t timebase_info = {0,0};
		if (timebase_info.denom == 0)
			mach_timebase_info(&timebase_info);
		boost::uint64_t at = mach_absolute_time();
		// make sure we don't overflow
		TORRENT_ASSERT((at >= 0 && at >= at / 1000 * timebase_info.numer / timebase_info.denom)
			|| (at < 0 && at < at / 1000 * timebase_info.numer / timebase_info.denom));
		return ptime(at / 1000 * timebase_info.numer / timebase_info.denom);
	}
}
#elif defined TORRENT_USE_QUERY_PERFORMANCE_TIMER

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	namespace aux
	{
		boost::int64_t performance_counter_to_microseconds(boost::int64_t pc)
		{
			static LARGE_INTEGER performace_counter_frequency = {0,0};
			if (performace_counter_frequency.QuadPart == 0)
				QueryPerformanceFrequency(&performace_counter_frequency);

#ifdef TORRENT_DEBUG
			// make sure we don't overflow
			boost::int64_t ret = (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
			TORRENT_ASSERT((pc >= 0 && pc >= ret) || (pc < 0 && pc < ret));
#endif
			return (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
		}

		boost::int64_t microseconds_to_performance_counter(boost::int64_t ms)
		{
			static LARGE_INTEGER performace_counter_frequency = {0,0};
			if (performace_counter_frequency.QuadPart == 0)
				QueryPerformanceFrequency(&performace_counter_frequency);
#ifdef TORRENT_DEBUG
			// make sure we don't overflow
			boost::int64_t ret = (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
			TORRENT_ASSERT((ms >= 0 && ms <= ret)
				|| (ms < 0 && ms > ret));
#endif
			return (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
		}
	}

	ptime time_now_hires()
	{
		LARGE_INTEGER now;
		QueryPerformanceCounter(&now);
		return ptime(now.QuadPart);
	}
}

#elif defined TORRENT_USE_CLOCK_GETTIME

#include <time.h>
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	ptime time_now_hires()
	{
		timespec ts;
		clock_gettime(CLOCK_MONOTONIC, &ts);
		return ptime(boost::uint64_t(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000);
	}
}

#elif defined TORRENT_USE_SYSTEM_TIME

#include <kernel/OS.h>

namespace libtorrent
{
	ptime time_now_hires()
	{ return ptime(system_time()); }
}

#endif // TORRENT_USE_SYSTEM_TIME

#endif // TORRENT_USE_BOOST_DATE_TIME

<commit_msg>fix windows DLL build<commit_after>/*

Copyright (c) 2009, Arvid Norberg
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 the author 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.

*/

#include <ctime>
#include <string>
#include <cstdio>
#include <boost/limits.hpp>
#include <boost/version.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/time.hpp"

#ifndef _WIN32
#include <unistd.h>
#endif

namespace libtorrent
{
	namespace aux
	{
		// used to cache the current time
		// every 100 ms. This is cheaper
		// than a system call and can be
		// used where more accurate time
		// is not necessary
		ptime g_current_time;
	}

	TORRENT_EXPORT ptime const& time_now() { return aux::g_current_time; }

	char const* time_now_string()
	{
//		time_t t = std::time(0);
//		tm* timeinfo = std::localtime(&t);
//		static char str[200];
//		std::strftime(str, 200, "%b %d %X", timeinfo);
//		return str;

		static const ptime start = time_now_hires();
		static char ret[200];
		int t = total_milliseconds(time_now_hires() - start);
		int h = t / 1000 / 60 / 60;
		t -= h * 60 * 60 * 1000;
		int m = t / 1000 / 60;
		t -= m * 60 * 1000;
		int s = t / 1000;
		t -= s * 1000;
		int ms = t;
		snprintf(ret, sizeof(ret), "%02d:%02d:%02d.%03d", h, m, s, ms);
		return ret;
	}

	std::string log_time()
	{
		static const ptime start = time_now_hires();
		char ret[200];
		snprintf(ret, sizeof(ret), "%"PRId64, total_microseconds(time_now_hires() - start));
		return ret;
	}
}

#if defined TORRENT_USE_BOOST_DATE_TIME

#include <boost/date_time/microsec_time_clock.hpp>

namespace libtorrent
{
	ptime time_now_hires()
	{ return boost::date_time::microsec_clock<ptime>::universal_time(); }
	ptime min_time()
	{ return boost::posix_time::ptime(boost::posix_time::min_date_time); }
	ptime max_time()
	{ return boost::posix_time::ptime(boost::posix_time::max_date_time); }
	time_duration seconds(int s) { return boost::posix_time::seconds(s); }
	time_duration milliseconds(int s) { return boost::posix_time::milliseconds(s); }
	time_duration microsec(int s) { return boost::posix_time::microsec(s); }
	time_duration minutes(int s) { return boost::posix_time::minutes(s); }
	time_duration hours(int s) { return boost::posix_time::hours(s); }

	int total_seconds(time_duration td)
	{ return td.total_seconds(); }
	int total_milliseconds(time_duration td)
	{ return td.total_milliseconds(); }
	boost::int64_t total_microseconds(time_duration td)
	{ return td.total_microseconds(); }
}

#else // TORRENT_USE_BOOST_DATE_TIME

namespace libtorrent
{
	ptime min_time() { return ptime(0); }
	ptime max_time() { return ptime((std::numeric_limits<boost::uint64_t>::max)()); }
}

#if defined TORRENT_USE_ABSOLUTE_TIME

#include <mach/mach_time.h>
#include <boost/cstdint.hpp>
#include "libtorrent/assert.hpp"

// high precision timer for darwin intel and ppc

namespace libtorrent
{
	ptime time_now_hires()
	{
		static mach_timebase_info_data_t timebase_info = {0,0};
		if (timebase_info.denom == 0)
			mach_timebase_info(&timebase_info);
		boost::uint64_t at = mach_absolute_time();
		// make sure we don't overflow
		TORRENT_ASSERT((at >= 0 && at >= at / 1000 * timebase_info.numer / timebase_info.denom)
			|| (at < 0 && at < at / 1000 * timebase_info.numer / timebase_info.denom));
		return ptime(at / 1000 * timebase_info.numer / timebase_info.denom);
	}
}
#elif defined TORRENT_USE_QUERY_PERFORMANCE_TIMER

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	namespace aux
	{
		boost::int64_t performance_counter_to_microseconds(boost::int64_t pc)
		{
			static LARGE_INTEGER performace_counter_frequency = {0,0};
			if (performace_counter_frequency.QuadPart == 0)
				QueryPerformanceFrequency(&performace_counter_frequency);

#ifdef TORRENT_DEBUG
			// make sure we don't overflow
			boost::int64_t ret = (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
			TORRENT_ASSERT((pc >= 0 && pc >= ret) || (pc < 0 && pc < ret));
#endif
			return (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
		}

		boost::int64_t microseconds_to_performance_counter(boost::int64_t ms)
		{
			static LARGE_INTEGER performace_counter_frequency = {0,0};
			if (performace_counter_frequency.QuadPart == 0)
				QueryPerformanceFrequency(&performace_counter_frequency);
#ifdef TORRENT_DEBUG
			// make sure we don't overflow
			boost::int64_t ret = (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
			TORRENT_ASSERT((ms >= 0 && ms <= ret)
				|| (ms < 0 && ms > ret));
#endif
			return (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
		}
	}

	ptime time_now_hires()
	{
		LARGE_INTEGER now;
		QueryPerformanceCounter(&now);
		return ptime(now.QuadPart);
	}
}

#elif defined TORRENT_USE_CLOCK_GETTIME

#include <time.h>
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	ptime time_now_hires()
	{
		timespec ts;
		clock_gettime(CLOCK_MONOTONIC, &ts);
		return ptime(boost::uint64_t(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000);
	}
}

#elif defined TORRENT_USE_SYSTEM_TIME

#include <kernel/OS.h>

namespace libtorrent
{
	ptime time_now_hires()
	{ return ptime(system_time()); }
}

#endif // TORRENT_USE_SYSTEM_TIME

#endif // TORRENT_USE_BOOST_DATE_TIME

<|endoftext|>


<commit_before>#include <string>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>

#include <zombye/core/game.hpp>
#include <zombye/rendering/mesh.hpp>
#include <zombye/rendering/rendering_system.hpp>
#include <zombye/utils/component_helper.hpp>
#include <zombye/utils/logger.hpp>

namespace zombye {
    rendering_system::rendering_system(game& game, SDL_Window* window)
    : game_{game}, window_{window}, mesh_manager_{game_}, shader_manager_{game_}, skinned_mesh_manager_{game_},
    skeleton_manager_{game_}, texture_manager_{game_}, active_camera_{0}, projection_{1.f}, view_{1.f} {
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

        context_ = SDL_GL_CreateContext(window_);
        auto error = std::string{SDL_GetError()};
        if (error != "") {
            log(LOG_FATAL, "could not create OpenGL context with version 3.1: " + error);
        }
        SDL_ClearError();

        SDL_GL_SetSwapInterval(1);

        glewExperimental = GL_TRUE;
        if (glewInit() != GLEW_OK) {
            log(LOG_FATAL, "could not initialize glew");
        }

        auto version = std::string{reinterpret_cast<const char*>(glGetString(GL_VERSION))};
        log("OpenGL version " + version);

        glEnable(GL_DEPTH_TEST);
        clear_color(0.4, 0.5, 0.9, 1.0);

        auto vertex_shader = shader_manager_.load("shader/staticmesh.vs", GL_VERTEX_SHADER);
        auto fragment_shader = shader_manager_.load("shader/staticmesh.fs", GL_FRAGMENT_SHADER);

        staticmesh_program_ = std::make_unique<program>();
        staticmesh_program_->attach_shader(vertex_shader);
        staticmesh_program_->attach_shader(fragment_shader);

        staticmesh_layout_.emplace_back("position", 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 0);
        staticmesh_layout_.emplace_back("texcoord", 2, GL_FLOAT, GL_FALSE, sizeof(vertex), 3 * sizeof(float));
        staticmesh_layout_.emplace_back("normal", 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 5 * sizeof(float));

        staticmesh_layout_.setup_program(*staticmesh_program_, "fragcolor");
        staticmesh_program_->link();

        vertex_shader = shader_manager_.load("shader/animation.vs", GL_VERTEX_SHADER);
        fragment_shader = shader_manager_.load("shader/animation.fs", GL_FRAGMENT_SHADER);

        animation_program_ = std::make_unique<program>();
        animation_program_->attach_shader(vertex_shader);
        animation_program_->attach_shader(fragment_shader);

        skinnedmesh_layout_.emplace_back("position", 3, GL_FLOAT, GL_FALSE, sizeof(skinned_vertex), 0);
        skinnedmesh_layout_.emplace_back("texcoord", 2, GL_FLOAT, GL_FALSE, sizeof(skinned_vertex), 3 * sizeof(float));
        skinnedmesh_layout_.emplace_back("normal", 3, GL_FLOAT, GL_FALSE, sizeof(skinned_vertex), 5 * sizeof(float));
        skinnedmesh_layout_.emplace_back("index", 4, GL_INT, GL_FALSE, sizeof(skinned_vertex), 8 * sizeof(float));
        skinnedmesh_layout_.emplace_back("weight", 4, GL_FLOAT, GL_FALSE, sizeof(skinned_vertex), 12 * sizeof(float));

        skinnedmesh_layout_.setup_program(*animation_program_, "fragcolor");
        animation_program_->link();

        float fovy = 45.f * 3.1415f / 180.f;
        auto width = float(game_.width());
        auto height = float(game_.height());
        float aspect = width / height;
        float near = 0.01f;
        float far = 1000.f;
        projection_ = glm::perspective(fovy, aspect, near, far);
        ortho_projection_ = glm::ortho(0.f, width, 0.f, height);

        g_buffer_ = std::make_unique<framebuffer>();
        g_buffer_->attach(GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, GL_DEPTH_COMPONENT24, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
        g_buffer_->attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, GL_RGBA32F, width, height, GL_RGBA, GL_FLOAT);
        g_buffer_->attach(GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, GL_RGBA32F, width, height, GL_RGBA, GL_FLOAT);
        g_buffer_->attach(GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, GL_RGBA32F, width, height, GL_RGBA, GL_FLOAT);

        g_buffer_->bind();
        glClearColor(0.4f, 0.6f, 0.9f, 1.f);
        GLenum buf[5] = {
            GL_COLOR_ATTACHMENT0,
            GL_COLOR_ATTACHMENT1,
            GL_COLOR_ATTACHMENT2,
            GL_NONE
        };
        glDrawBuffers(5, buf);
        g_buffer_->bind_default();
    }

    rendering_system::~rendering_system() {
        window_ = nullptr;
        SDL_GL_DeleteContext(context_);
    }

    void rendering_system::begin_scene() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }

    void rendering_system::end_scene() {
        SDL_GL_SwapWindow(window_);
    }

    void rendering_system::update(float delta_time) {
        auto camera = camera_components_.find(active_camera_);
        view_ = glm::mat4{1.f};
        auto camera_position = glm::vec3{0.f};
        if (camera != camera_components_.end()) {
            view_ = camera->second->transform();
            camera_position = camera->second->owner().position();
        }

        std::vector<glm::vec3> light_positions;
        std::vector<glm::vec3> light_colors;
        std::vector<float> light_distances;
        auto i = 0;
        for (auto& l : light_components_) {
            if (i > 15) {
                break;
            }
            light_positions.emplace_back(l->owner().position());
            light_colors.emplace_back(l->color());
            light_distances.emplace_back(l->distance());
        }
        int light_count = light_positions.size();

        staticmesh_program_->use();
        staticmesh_program_->uniform("diffuse_sampler", 0);
        staticmesh_program_->uniform("specular_sampler", 1);
        staticmesh_program_->uniform("light_count", light_count);
        staticmesh_program_->uniform("light_position", light_count, light_positions);
        staticmesh_program_->uniform("light_color", light_count, light_colors);
        staticmesh_program_->uniform("light_distance", light_count, light_distances);
        staticmesh_program_->uniform("view", camera_position);
        for (auto& s : staticmesh_components_) {
            auto model = s->owner().transform();
            auto model_it = glm::inverse(glm::transpose(model));
            staticmesh_program_->uniform("m", false, model);
            staticmesh_program_->uniform("mit", false, model_it);
            staticmesh_program_->uniform("mvp", false, projection_ * view_ * model);
            s->draw();
        }

        animation_program_->use();
        animation_program_->uniform("diffuse_sampler", 0);
        animation_program_->uniform("specular_sampler", 1);
        animation_program_->uniform("light_count", light_count);
        animation_program_->uniform("light_position", light_count, light_positions);
        animation_program_->uniform("light_color", light_count, light_colors);
        animation_program_->uniform("light_distance", light_count, light_distances);
        animation_program_->uniform("view", camera_position);
        for (auto& a: animation_components_) {
            auto model = a->owner().transform();
            auto model_it = glm::inverse(glm::transpose(model));
            animation_program_->uniform("m", false, model);
            animation_program_->uniform("mit", false, model_it);
            animation_program_->uniform("mvp", false, projection_ * view_ * model);
            animation_program_->uniform("pose", a->pose().size(), false, a->pose());
            a->draw();
        }
    }

    void rendering_system::clear_color(float red, float green, float blue, float alpha) {
        glClearColor(red, green, blue, alpha);
    }

    void rendering_system::register_component(animation_component* component) {
        animation_components_.emplace_back(component);
    }

    void rendering_system::unregister_component(animation_component* component) {
        remove(animation_components_, component);
    }

    void rendering_system::register_component(camera_component* component) {
        camera_components_.insert(std::make_pair(component->owner().id(), component));
    }

    void rendering_system::unregister_component(camera_component* component) {
        auto it = camera_components_.find(component->owner().id());
        if (it != camera_components_.end()) {
            camera_components_.erase(it);
        }
    }

    void rendering_system::register_component(light_component* component) {
        light_components_.emplace_back(component);
    }

    void rendering_system::unregister_component(light_component* component) {
        remove(light_components_, component);
    }

    void rendering_system::register_component(staticmesh_component* component) {
        staticmesh_components_.emplace_back(component);
    }

    void rendering_system::unregister_component(staticmesh_component* component) {
        remove(staticmesh_components_, component);
    }
}
<commit_msg>init debug screen quads<commit_after>#include <string>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>

#include <zombye/core/game.hpp>
#include <zombye/rendering/mesh.hpp>
#include <zombye/rendering/rendering_system.hpp>
#include <zombye/utils/component_helper.hpp>
#include <zombye/utils/logger.hpp>

namespace zombye {
    rendering_system::rendering_system(game& game, SDL_Window* window)
    : game_{game}, window_{window}, mesh_manager_{game_}, shader_manager_{game_}, skinned_mesh_manager_{game_},
    skeleton_manager_{game_}, texture_manager_{game_}, active_camera_{0}, projection_{1.f}, view_{1.f} {
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

        context_ = SDL_GL_CreateContext(window_);
        auto error = std::string{SDL_GetError()};
        if (error != "") {
            log(LOG_FATAL, "could not create OpenGL context with version 3.1: " + error);
        }
        SDL_ClearError();

        SDL_GL_SetSwapInterval(1);

        glewExperimental = GL_TRUE;
        if (glewInit() != GLEW_OK) {
            log(LOG_FATAL, "could not initialize glew");
        }

        auto version = std::string{reinterpret_cast<const char*>(glGetString(GL_VERSION))};
        log("OpenGL version " + version);

        glEnable(GL_DEPTH_TEST);
        clear_color(0.4, 0.5, 0.9, 1.0);

        auto vertex_shader = shader_manager_.load("shader/staticmesh.vs", GL_VERTEX_SHADER);
        auto fragment_shader = shader_manager_.load("shader/staticmesh.fs", GL_FRAGMENT_SHADER);

        staticmesh_program_ = std::make_unique<program>();
        staticmesh_program_->attach_shader(vertex_shader);
        staticmesh_program_->attach_shader(fragment_shader);

        staticmesh_layout_.emplace_back("position", 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 0);
        staticmesh_layout_.emplace_back("texcoord", 2, GL_FLOAT, GL_FALSE, sizeof(vertex), 3 * sizeof(float));
        staticmesh_layout_.emplace_back("normal", 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 5 * sizeof(float));

        staticmesh_layout_.setup_program(*staticmesh_program_, "fragcolor");
        staticmesh_program_->link();

        vertex_shader = shader_manager_.load("shader/animation.vs", GL_VERTEX_SHADER);
        fragment_shader = shader_manager_.load("shader/animation.fs", GL_FRAGMENT_SHADER);

        animation_program_ = std::make_unique<program>();
        animation_program_->attach_shader(vertex_shader);
        animation_program_->attach_shader(fragment_shader);

        skinnedmesh_layout_.emplace_back("position", 3, GL_FLOAT, GL_FALSE, sizeof(skinned_vertex), 0);
        skinnedmesh_layout_.emplace_back("texcoord", 2, GL_FLOAT, GL_FALSE, sizeof(skinned_vertex), 3 * sizeof(float));
        skinnedmesh_layout_.emplace_back("normal", 3, GL_FLOAT, GL_FALSE, sizeof(skinned_vertex), 5 * sizeof(float));
        skinnedmesh_layout_.emplace_back("index", 4, GL_INT, GL_FALSE, sizeof(skinned_vertex), 8 * sizeof(float));
        skinnedmesh_layout_.emplace_back("weight", 4, GL_FLOAT, GL_FALSE, sizeof(skinned_vertex), 12 * sizeof(float));

        skinnedmesh_layout_.setup_program(*animation_program_, "fragcolor");
        animation_program_->link();

        float fovy = 45.f * 3.1415f / 180.f;
        auto width = float(game_.width());
        auto height = float(game_.height());
        float aspect = width / height;
        float near = 0.01f;
        float far = 1000.f;
        projection_ = glm::perspective(fovy, aspect, near, far);
        ortho_projection_ = glm::ortho(0.f, width, 0.f, height);

        g_buffer_ = std::make_unique<framebuffer>();
        g_buffer_->attach(GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, GL_DEPTH_COMPONENT24, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
        g_buffer_->attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, GL_RGBA32F, width, height, GL_RGBA, GL_FLOAT);
        g_buffer_->attach(GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, GL_RGBA32F, width, height, GL_RGBA, GL_FLOAT);
        g_buffer_->attach(GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, GL_RGBA32F, width, height, GL_RGBA, GL_FLOAT);

        g_buffer_->bind();
        glClearColor(0.4f, 0.6f, 0.9f, 1.f);
        GLenum buf[5] = {
            GL_COLOR_ATTACHMENT0,
            GL_COLOR_ATTACHMENT1,
            GL_COLOR_ATTACHMENT2,
            GL_NONE
        };
        glDrawBuffers(5, buf);
        g_buffer_->bind_default();

        screen_quad_program_ = std::make_unique<program>();
        vertex_shader = shader_manager_.load("shader/screen_quad.vs", GL_VERTEX_SHADER);
        if (!vertex_shader) {
            throw std::runtime_error{"could not load screen_quad.vs"};
        }
        screen_quad_program_->attach_shader(vertex_shader);
        fragment_shader = shader_manager_.load("shader/screen_quad.fs", GL_FRAGMENT_SHADER);
        if (!fragment_shader) {
            throw std::runtime_error{"could not load screen_quad.fs"};
        }
        screen_quad_program_->attach_shader(fragment_shader);
        staticmesh_layout_.setup_program(*screen_quad_program_, "frag_color");
        screen_quad_program_->link();

        for (auto i = 0; i < 4; ++i) {
            debug_screen_quads_.emplace_back(std::make_unique<screen_quad>(
                staticmesh_layout_,
                glm::vec2{(i * width / 4.f) + 0.01f * width, (3 * height / 4) + 0.01f * height},
                glm::vec2{((i + 1) * width / 4.f) - 0.01f * width, height - 0.01f * height}
            ));
        }
    }

    rendering_system::~rendering_system() {
        window_ = nullptr;
        SDL_GL_DeleteContext(context_);
    }

    void rendering_system::begin_scene() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }

    void rendering_system::end_scene() {
        SDL_GL_SwapWindow(window_);
    }

    void rendering_system::update(float delta_time) {
        auto camera = camera_components_.find(active_camera_);
        view_ = glm::mat4{1.f};
        auto camera_position = glm::vec3{0.f};
        if (camera != camera_components_.end()) {
            view_ = camera->second->transform();
            camera_position = camera->second->owner().position();
        }

        std::vector<glm::vec3> light_positions;
        std::vector<glm::vec3> light_colors;
        std::vector<float> light_distances;
        auto i = 0;
        for (auto& l : light_components_) {
            if (i > 15) {
                break;
            }
            light_positions.emplace_back(l->owner().position());
            light_colors.emplace_back(l->color());
            light_distances.emplace_back(l->distance());
        }
        int light_count = light_positions.size();

        staticmesh_program_->use();
        staticmesh_program_->uniform("diffuse_sampler", 0);
        staticmesh_program_->uniform("specular_sampler", 1);
        staticmesh_program_->uniform("light_count", light_count);
        staticmesh_program_->uniform("light_position", light_count, light_positions);
        staticmesh_program_->uniform("light_color", light_count, light_colors);
        staticmesh_program_->uniform("light_distance", light_count, light_distances);
        staticmesh_program_->uniform("view", camera_position);
        for (auto& s : staticmesh_components_) {
            auto model = s->owner().transform();
            auto model_it = glm::inverse(glm::transpose(model));
            staticmesh_program_->uniform("m", false, model);
            staticmesh_program_->uniform("mit", false, model_it);
            staticmesh_program_->uniform("mvp", false, projection_ * view_ * model);
            s->draw();
        }

        animation_program_->use();
        animation_program_->uniform("diffuse_sampler", 0);
        animation_program_->uniform("specular_sampler", 1);
        animation_program_->uniform("light_count", light_count);
        animation_program_->uniform("light_position", light_count, light_positions);
        animation_program_->uniform("light_color", light_count, light_colors);
        animation_program_->uniform("light_distance", light_count, light_distances);
        animation_program_->uniform("view", camera_position);
        for (auto& a: animation_components_) {
            auto model = a->owner().transform();
            auto model_it = glm::inverse(glm::transpose(model));
            animation_program_->uniform("m", false, model);
            animation_program_->uniform("mit", false, model_it);
            animation_program_->uniform("mvp", false, projection_ * view_ * model);
            animation_program_->uniform("pose", a->pose().size(), false, a->pose());
            a->draw();
        }
    }

    void rendering_system::clear_color(float red, float green, float blue, float alpha) {
        glClearColor(red, green, blue, alpha);
    }

    void rendering_system::register_component(animation_component* component) {
        animation_components_.emplace_back(component);
    }

    void rendering_system::unregister_component(animation_component* component) {
        remove(animation_components_, component);
    }

    void rendering_system::register_component(camera_component* component) {
        camera_components_.insert(std::make_pair(component->owner().id(), component));
    }

    void rendering_system::unregister_component(camera_component* component) {
        auto it = camera_components_.find(component->owner().id());
        if (it != camera_components_.end()) {
            camera_components_.erase(it);
        }
    }

    void rendering_system::register_component(light_component* component) {
        light_components_.emplace_back(component);
    }

    void rendering_system::unregister_component(light_component* component) {
        remove(light_components_, component);
    }

    void rendering_system::register_component(staticmesh_component* component) {
        staticmesh_components_.emplace_back(component);
    }

    void rendering_system::unregister_component(staticmesh_component* component) {
        remove(staticmesh_components_, component);
    }
}
<|endoftext|>


<commit_before>#include "util.h"

#include <iomanip>
#include <ostream>

// TODO: Currently throwing compiler exceptions by pointer in order
// to maintain alignment requirements of BID_UINT128 type on some
// platforms. See https://stackoverflow.com/questions/30885997/clang-runtime-fault-when-throwing-aligned-type-compiler-bug
// for full explanation.

void abort_error(const char *compiler_file, int compiler_line, int number, const Token &token, const std::string &message)
{
    throw new SourceError(compiler_file, compiler_line, number, token, message);
}

void abort_error_a(const char *compiler_file, int compiler_line, int number, const Token &token_before, const Token &token, const std::string &message)
{
    if (token_before.line == token.line) {
        throw new SourceError(compiler_file, compiler_line, number, token, message);
    }
    Token tok = token_before;
    tok.column = static_cast<int>(1 + tok.source.length());
    if (tok.source[tok.source.length()-1] != ' ') {
        tok.column++;
    }
    throw new SourceError(compiler_file, compiler_line, number, tok, message);
}

void abort_error(const char *compiler_file, int compiler_line, int number, const Token &token, const std::string &message, const Token &token2, const std::string &message2)
{
    throw new SourceError(compiler_file, compiler_line, number, token, message, token2, message2);
}

void abort_internal_error(const char *compiler_file, int compiler_line, const std::string &message)
{
    throw new InternalError(compiler_file, compiler_line, message);
}

void InternalError::write(std::ostream &out)
{
    out << "Compiler Internal Error: " << message << " (" << compiler_file << ":" << compiler_line << ")\n";
}

void SourceError::write(std::ostream &out)
{
    out << "Error in file: " << token.file << "\n";
    out << "\n";
    out << token.line << "| " << token.source << "\n";
    out << std::setw(std::to_string(token.line).length()+2+token.column) << "^" << "\n";
    out << "Error N" << number << ": " << token.line << ":" << token.column << " " << message << " (" << compiler_file << ":" << compiler_line << ")\n";
    if (token2.type != NONE) {
        out << "\n";
        out << "Related line information:\n";
        out << "\n";
        out << token2.line << "| " << token2.source << "\n";
        out << std::setw(std::to_string(token2.line).length()+2+token2.column) << "^" << "\n";
        out << "Error N" << number << ": " << token2.line << ":" << token2.column << " " << message2 << "\n";
    }
}
<commit_msg>Remove compiler source line information from error messages<commit_after>#include "util.h"

#include <iomanip>
#include <ostream>

// TODO: Currently throwing compiler exceptions by pointer in order
// to maintain alignment requirements of BID_UINT128 type on some
// platforms. See https://stackoverflow.com/questions/30885997/clang-runtime-fault-when-throwing-aligned-type-compiler-bug
// for full explanation.

void abort_error(const char *compiler_file, int compiler_line, int number, const Token &token, const std::string &message)
{
    throw new SourceError(compiler_file, compiler_line, number, token, message);
}

void abort_error_a(const char *compiler_file, int compiler_line, int number, const Token &token_before, const Token &token, const std::string &message)
{
    if (token_before.line == token.line) {
        throw new SourceError(compiler_file, compiler_line, number, token, message);
    }
    Token tok = token_before;
    tok.column = static_cast<int>(1 + tok.source.length());
    if (tok.source[tok.source.length()-1] != ' ') {
        tok.column++;
    }
    throw new SourceError(compiler_file, compiler_line, number, tok, message);
}

void abort_error(const char *compiler_file, int compiler_line, int number, const Token &token, const std::string &message, const Token &token2, const std::string &message2)
{
    throw new SourceError(compiler_file, compiler_line, number, token, message, token2, message2);
}

void abort_internal_error(const char *compiler_file, int compiler_line, const std::string &message)
{
    throw new InternalError(compiler_file, compiler_line, message);
}

void InternalError::write(std::ostream &out)
{
    out << "Compiler Internal Error: " << message << " (" << compiler_file << ":" << compiler_line << ")\n";
}

void SourceError::write(std::ostream &out)
{
    out << "Error in file: " << token.file << "\n";
    out << "\n";
    out << token.line << "| " << token.source << "\n";
    out << std::setw(std::to_string(token.line).length()+2+token.column) << "^" << "\n";
    out << "Error N" << number << ": " << token.line << ":" << token.column << " " << message << "\n";
    if (token2.type != NONE) {
        out << "\n";
        out << "Related line information:\n";
        out << "\n";
        out << token2.line << "| " << token2.source << "\n";
        out << std::setw(std::to_string(token2.line).length()+2+token2.column) << "^" << "\n";
        out << "Error N" << number << ": " << token2.line << ":" << token2.column << " " << message2 << "\n";
    }
}
<|endoftext|>


<commit_before>#include <Rcpp.h>

#if defined(_WIN32)
#undef Realloc
#undef Free
#include <Windows.h>

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#if defined(BSD)
#include <sys/sysctl.h>
#endif

#endif

#include <sys/time.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>

extern "C" {
    #include "scrypt_platform.h"
    #include "crypto/crypto_scrypt.h"
}

#include "util.hpp"

#ifdef HAVE_CLOCK_GETTIME

static clock_t clocktouse;

static int getclockres(double *resd)
{
    struct timespec res;

    /*
     * Try clocks in order of preference until we find one which works.
     * (We assume that if clock_getres works, clock_gettime will, too.)
     * The use of if/else/if/else/if/else rather than if/elif/elif/else
     * is ugly but legal, and allows us to #ifdef things appropriately.
     */
#ifdef CLOCK_VIRTUAL
    if (clock_getres(CLOCK_VIRTUAL, &res) == 0)
        clocktouse = CLOCK_VIRTUAL;
    else
#endif
#ifdef CLOCK_MONOTONIC
    if (clock_getres(CLOCK_MONOTONIC, &res) == 0)
        clocktouse = CLOCK_MONOTONIC;
    else
#endif
    if (clock_getres(CLOCK_REALTIME, &res) == 0)
        clocktouse = CLOCK_REALTIME;
    else
        return (-1);

    /* Convert clock resolution to a double. */
    *resd = res.tv_sec + res.tv_nsec * 0.000000001;

    return (0);
}

static int getclocktime(struct timespec *ts)
{

#ifdef DEBUG
    REprintf("Using clock_gettime()\n");
#endif

    if (clock_gettime(clocktouse, ts))
        return (-1);

    return (0);
}

#else

static int getclockres(double *resd)
{

#ifdef DEBUG
    REprintf("Using gettimeofday()\n");
#endif

    *resd = 1.0 / CLOCKS_PER_SEC;

    return (0);
}

static int getclocktime(struct timespec *ts)
{
    struct timeval tv;

    if (gettimeofday(&tv, NULL))
        return (-1);
    ts->tv_sec = tv.tv_sec;
    ts->tv_nsec = tv.tv_usec * 1000;

    return (0);
}

#endif

static int getclockdiff(struct timespec * st, double * diffd)
{
    struct timespec en;

    if (getclocktime(&en))
        return (1);
    *diffd = (en.tv_nsec - st->tv_nsec) * 0.000000001 +
        (en.tv_sec - st->tv_sec);

    return (0);
}

/*
 * Get CPU performance
 *
 * This function is derived from Colin Percival's scrypt reference code
 */
int getcpuperf(double *opps)
{
    struct timespec st;
    double resd, diffd;
    uint64_t i = 0;

    /* Get the clock resolution. */
    if (getclockres(&resd))
        return (2);

#ifdef DEBUG
    REprintf("Clock resolution is %f\n", resd);
#endif

    /* Loop until the clock ticks. */
    if (getclocktime(&st))
        return (2);
    do {
        /* Do an scrypt. */
        if (crypto_scrypt(NULL, 0, NULL, 0, 16, 1, 1, NULL, 0))
            return (3);

        /* Has the clock ticked? */
        if (getclockdiff(&st, &diffd))
            return (2);
        if (diffd > 0)
            break;
    } while (1);

    /* Could how many scryps we can do before the next tick. */
    if (getclocktime(&st))
        return (2);
    do {
        /* Do an scrypt. */
        if (crypto_scrypt(NULL, 0, NULL, 0, 128, 1, 1, NULL, 0))
            return (3);

        /* We invoked the salsa20/8 core 512 times. */
        i += 512;

        /* Check if we have looped for long enough. */
        if (getclockdiff(&st, &diffd))
            return (2);
        if (diffd > resd)
            break;
    } while (1);

#ifdef DEBUG
    REprintf("%ju salsa20/8 cores performed in %f seconds\n",
        (uintmax_t)i, diffd);
#endif

    /* We can do approximately i salsa20/8 cores per diffd seconds. */
    *opps = i / diffd;
    return (0);
}

/*
 * Get available memory
 *
 * This function is dervied from:
 * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
 */
int getmemlimit(size_t *memlimit) {

#if defined(_WIN32) && (defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW__) || defined(__MINGW32__) )
    /* Cygwin under Windows. ------------------------------------ */
    /* New 64-bit MEMORYSTATUSEX isn't available.  Use old 32.bit */
    MEMORYSTATUS status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatus( &status );
    *memlimit = (size_t)status.dwTotalPhys;
    return 0;

#elif defined(_WIN32)
    /* Windows. ------------------------------------------------- */
    /* Use new 64-bit MEMORYSTATUSEX, not old 32-bit MEMORYSTATUS */
    MEMORYSTATUSEX status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatusEx( &status );
    *memlimit = (size_t)status.ullTotalPhys;
    return 0;

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
    /* UNIX variants. ------------------------------------------- */

#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
    int mib[2];
    mib[0] = CTL_HW;
#if defined(HW_MEMSIZE)
    mib[1] = HW_MEMSIZE;    // OSX
#elif defined(HW_PHYSMEM64)
    mib[1] = HW_PHYSMEM64;  // NetBSD, OpenBSD
#endif
    int64_t size = 0;       // 64-bit
    size_t len = sizeof( size );
    if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 ) {
        *memlimit = (size_t)size;
        return 0;
    }
    return -1; // Failure

#elif defined(_SC_AIX_REALMEM)
    /* AIX. ----------------------------------------------------- */
    *memlimit = (size_t)sysconf( _SC_AIX_REALMEM ) * (size_t)1024L;
    return 0;

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
    /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
    *memlimit = (size_t)sysconf( _SC_PHYS_PAGES ) * (size_t)sysconf( _SC_PAGESIZE );
    return 0;

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGE_SIZE)
    /* Legacy. -------------------------------------------------- */
    *memlimit = (size_t)sysconf( _SC_PHYS_PAGES ) * (size_t)sysconf( _SC_PAGE_SIZE );
    return 0;

#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
    /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
    int mib[2];
    mib[0] = CTL_HW;
#if defined(HW_REALMEM)
    mib[1] = HW_REALMEM;        // FreeBSD
#elif defined(HW_PYSMEM)
    mib[1] = HW_PHYSMEM;        // Others
#endif
    unsigned int size = 0;      // 32-bit
    size_t len = sizeof( size );
    if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 ) {
        *memlimit = (size_t)size;
        return 0;
    }
    return -1; // Failure
#endif

#else
    return -2; // Unknown OS
#endif

}

/*
 * Obtains salt for password hash.
 * This function is derived from Colin Percival's scrypt reference code
 */
int getsalt(uint8_t salt[32]) {

    uint8_t *buf = salt;
    size_t buflen = 32;

#if defined(_WIN32)

    HCRYPTPROV hCryptCtx;

    if (CryptAcquireContext(&hCryptCtx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
        if (!CryptGenRandom(hCryptCtx, buflen, buf))
            goto err;
        CryptReleaseContext(hCryptCtx, 0);
    } else {
        goto err;
    }

    /* Success! */
    return (0);

#else

    int fd;
    ssize_t lenread;

    /* Open /dev/urandom */
    if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
        goto err;

    /* Read bytes until we have filled the buffer */
    while (buflen > 0) {
        if ((lenread = read(fd, buf, buflen)) == -1)
            goto close;

        /* The random device should never EOF */
        if (lenread == 0)
            goto close;

        /* We're partly done */
        buf += lenread;
        buflen -= lenread;
    }

    /* Close the device */
    while (close(fd) == -1) {
        if (errno != EINTR)
            goto err;
    }

    /* Success! */
    return (0);

close:
    close(fd);

#endif

err:
    /* Failure! */
    return (4);
}

<commit_msg>Add comment re strange #undefs<commit_after>#include <Rcpp.h>

#if defined(_WIN32)
// See: http://stackoverflow.com/questions/11588765/using-rcpp-with-windows-specific-includes
#undef Realloc
#undef Free
#include <Windows.h>

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#if defined(BSD)
#include <sys/sysctl.h>
#endif

#endif

#include <sys/time.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>

extern "C" {
    #include "scrypt_platform.h"
    #include "crypto/crypto_scrypt.h"
}

#include "util.hpp"

#ifdef HAVE_CLOCK_GETTIME

static clock_t clocktouse;

static int getclockres(double *resd)
{
    struct timespec res;

    /*
     * Try clocks in order of preference until we find one which works.
     * (We assume that if clock_getres works, clock_gettime will, too.)
     * The use of if/else/if/else/if/else rather than if/elif/elif/else
     * is ugly but legal, and allows us to #ifdef things appropriately.
     */
#ifdef CLOCK_VIRTUAL
    if (clock_getres(CLOCK_VIRTUAL, &res) == 0)
        clocktouse = CLOCK_VIRTUAL;
    else
#endif
#ifdef CLOCK_MONOTONIC
    if (clock_getres(CLOCK_MONOTONIC, &res) == 0)
        clocktouse = CLOCK_MONOTONIC;
    else
#endif
    if (clock_getres(CLOCK_REALTIME, &res) == 0)
        clocktouse = CLOCK_REALTIME;
    else
        return (-1);

    /* Convert clock resolution to a double. */
    *resd = res.tv_sec + res.tv_nsec * 0.000000001;

    return (0);
}

static int getclocktime(struct timespec *ts)
{

#ifdef DEBUG
    REprintf("Using clock_gettime()\n");
#endif

    if (clock_gettime(clocktouse, ts))
        return (-1);

    return (0);
}

#else

static int getclockres(double *resd)
{

#ifdef DEBUG
    REprintf("Using gettimeofday()\n");
#endif

    *resd = 1.0 / CLOCKS_PER_SEC;

    return (0);
}

static int getclocktime(struct timespec *ts)
{
    struct timeval tv;

    if (gettimeofday(&tv, NULL))
        return (-1);
    ts->tv_sec = tv.tv_sec;
    ts->tv_nsec = tv.tv_usec * 1000;

    return (0);
}

#endif

static int getclockdiff(struct timespec * st, double * diffd)
{
    struct timespec en;

    if (getclocktime(&en))
        return (1);
    *diffd = (en.tv_nsec - st->tv_nsec) * 0.000000001 +
        (en.tv_sec - st->tv_sec);

    return (0);
}

/*
 * Get CPU performance
 *
 * This function is derived from Colin Percival's scrypt reference code
 */
int getcpuperf(double *opps)
{
    struct timespec st;
    double resd, diffd;
    uint64_t i = 0;

    /* Get the clock resolution. */
    if (getclockres(&resd))
        return (2);

#ifdef DEBUG
    REprintf("Clock resolution is %f\n", resd);
#endif

    /* Loop until the clock ticks. */
    if (getclocktime(&st))
        return (2);
    do {
        /* Do an scrypt. */
        if (crypto_scrypt(NULL, 0, NULL, 0, 16, 1, 1, NULL, 0))
            return (3);

        /* Has the clock ticked? */
        if (getclockdiff(&st, &diffd))
            return (2);
        if (diffd > 0)
            break;
    } while (1);

    /* Could how many scryps we can do before the next tick. */
    if (getclocktime(&st))
        return (2);
    do {
        /* Do an scrypt. */
        if (crypto_scrypt(NULL, 0, NULL, 0, 128, 1, 1, NULL, 0))
            return (3);

        /* We invoked the salsa20/8 core 512 times. */
        i += 512;

        /* Check if we have looped for long enough. */
        if (getclockdiff(&st, &diffd))
            return (2);
        if (diffd > resd)
            break;
    } while (1);

#ifdef DEBUG
    REprintf("%ju salsa20/8 cores performed in %f seconds\n",
        (uintmax_t)i, diffd);
#endif

    /* We can do approximately i salsa20/8 cores per diffd seconds. */
    *opps = i / diffd;
    return (0);
}

/*
 * Get available memory
 *
 * This function is dervied from:
 * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
 */
int getmemlimit(size_t *memlimit) {

#if defined(_WIN32) && (defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW__) || defined(__MINGW32__) )
    /* Cygwin under Windows. ------------------------------------ */
    /* New 64-bit MEMORYSTATUSEX isn't available.  Use old 32.bit */
    MEMORYSTATUS status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatus( &status );
    *memlimit = (size_t)status.dwTotalPhys;
    return 0;

#elif defined(_WIN32)
    /* Windows. ------------------------------------------------- */
    /* Use new 64-bit MEMORYSTATUSEX, not old 32-bit MEMORYSTATUS */
    MEMORYSTATUSEX status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatusEx( &status );
    *memlimit = (size_t)status.ullTotalPhys;
    return 0;

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
    /* UNIX variants. ------------------------------------------- */

#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
    int mib[2];
    mib[0] = CTL_HW;
#if defined(HW_MEMSIZE)
    mib[1] = HW_MEMSIZE;    // OSX
#elif defined(HW_PHYSMEM64)
    mib[1] = HW_PHYSMEM64;  // NetBSD, OpenBSD
#endif
    int64_t size = 0;       // 64-bit
    size_t len = sizeof( size );
    if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 ) {
        *memlimit = (size_t)size;
        return 0;
    }
    return -1; // Failure

#elif defined(_SC_AIX_REALMEM)
    /* AIX. ----------------------------------------------------- */
    *memlimit = (size_t)sysconf( _SC_AIX_REALMEM ) * (size_t)1024L;
    return 0;

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
    /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
    *memlimit = (size_t)sysconf( _SC_PHYS_PAGES ) * (size_t)sysconf( _SC_PAGESIZE );
    return 0;

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGE_SIZE)
    /* Legacy. -------------------------------------------------- */
    *memlimit = (size_t)sysconf( _SC_PHYS_PAGES ) * (size_t)sysconf( _SC_PAGE_SIZE );
    return 0;

#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
    /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
    int mib[2];
    mib[0] = CTL_HW;
#if defined(HW_REALMEM)
    mib[1] = HW_REALMEM;        // FreeBSD
#elif defined(HW_PYSMEM)
    mib[1] = HW_PHYSMEM;        // Others
#endif
    unsigned int size = 0;      // 32-bit
    size_t len = sizeof( size );
    if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 ) {
        *memlimit = (size_t)size;
        return 0;
    }
    return -1; // Failure
#endif

#else
    return -2; // Unknown OS
#endif

}

/*
 * Obtains salt for password hash.
 * This function is derived from Colin Percival's scrypt reference code
 */
int getsalt(uint8_t salt[32]) {

    uint8_t *buf = salt;
    size_t buflen = 32;

#if defined(_WIN32)

    HCRYPTPROV hCryptCtx;

    if (CryptAcquireContext(&hCryptCtx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
        if (!CryptGenRandom(hCryptCtx, buflen, buf))
            goto err;
        CryptReleaseContext(hCryptCtx, 0);
    } else {
        goto err;
    }

    /* Success! */
    return (0);

#else

    int fd;
    ssize_t lenread;

    /* Open /dev/urandom */
    if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
        goto err;

    /* Read bytes until we have filled the buffer */
    while (buflen > 0) {
        if ((lenread = read(fd, buf, buflen)) == -1)
            goto close;

        /* The random device should never EOF */
        if (lenread == 0)
            goto close;

        /* We're partly done */
        buf += lenread;
        buflen -= lenread;
    }

    /* Close the device */
    while (close(fd) == -1) {
        if (errno != EINTR)
            goto err;
    }

    /* Success! */
    return (0);

close:
    close(fd);

#endif

err:
    /* Failure! */
    return (4);
}

<|endoftext|>