<commit_before>/*
 *  SnapFind
 *  An interactive image search application
 *  Version 1
 *
 *  Copyright (c) 2002-2005 Intel Corporation
 *  Copyright (c) 2007 Carnegie Mellon University
 *  All Rights Reserved.
 *
 *  This software is distributed under the terms of the Eclipse Public
 *  License, Version 1.0 which can be found in the file named LICENSE.
 *  ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS SOFTWARE CONSTITUTES
 *  RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
#include <sys/time.h>
#include <math.h>
#include <libgen.h>
#include <stdint.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>

#include "diamond_types.h"
#include "searchlet_api.h"
#include "lib_results.h"
#include "lib_sfimage.h"
#include "sf_consts.h"
#include "face_search.h"
#include "search_set.h"
#include "sfind_search.h"
#include "plugin.h"
#include "snapfind.h"

#include "lib_scope.h"

/*
 * this need to be global because we share it with the main
 * GUI.  XXX hack, do it right later.
 */
ls_search_handle_t shandle;
app_stats_t	astats;

/*
 * state the is global to all of these functions.
 */
/* XXX global for status window, fix  this someday */
int      search_active = 0;
static int     active  = 0;
int      search_number = 0;
struct timeval	search_start;

static search_set *sset = NULL;

/*
 * This initializes the search  state.
 */

void
init_search()
{
	shandle = ls_init_search();
	if (shandle == NULL) {
		printf("failed to initialize:  !! \n");
		exit(1);
	}
}

/*
 * This function initiates the search by building a filter
 * specification, setting the searchlet and then starting the search.
 */

void
do_search(gid_list_t * main_region, char *fspec)
{
	int             err;
	char           *filter_name;
	char           *dir_name;
	void 	       *cookie;
	search_iter_t iter;

	if (!fspec) {
		fspec = sset->build_filter_spec(NULL);
		if (fspec == NULL) {
			printf("failed to build filter specification \n");
			exit(1);
		}
	}

	dir_name = (char *) malloc(SF_MAX_PATH);
	if (dir_name == NULL) {
		exit(1);                /* XXX */
	}

	err = ls_set_searchlist(shandle, main_region->ngids,
				main_region->gids);
	if (err) {
		printf("Failed to set searchlist on  err %d \n", err);
		exit(1);
	}

	filter_name = first_searchlet_lib(&cookie);
	if (filter_name == NULL) {
		fprintf(stderr, "No filter libraries are defined \n");
		assert(0);
	}

	err = ls_set_searchlet(shandle, DEV_ISA_IA32, filter_name, fspec);
	if (err) {
		printf("Failed to set searchlet on err %d \n", err);
		exit(1);
	}
	free(filter_name);

	while ((filter_name = next_searchlet_lib(&cookie)) != NULL) {
		err = ls_add_filter_file(shandle, DEV_ISA_IA32, filter_name);
		free(filter_name);
	}

	/* Attach auxiliary data for this search.  */
	sset->write_blobs(shandle);

	/* reset application statistics */
	astats.as_objs_queued = 0;
	astats.as_objs_presented = 0;

	/* Go ahead and start the search.  */
	err = ls_start_search(shandle);
	if (err) {
		printf("Failed to start search on err %d \n", err);
		exit(1);
	}
}

/*
 *  Defines a scope for a new search.
 */
static void
define_scope(void *data)
{
	int             err;

	err = ls_define_scope();
	if (err != 0) {
		printf("XXX failed to define scope \n");
	}
}

/*
 *  Stops a currently executing search.
 */
static void
stop_search(void *data)
{
	int             err;

	static int		old_total = 0;

	astats.as_objs_presented = user_measurement.total_seen - old_total;
	old_total = user_measurement.total_seen;
	err = ls_terminate_search_extended(shandle, &astats);
	if (err != 0) {
		printf("XXX failed to terminate search \n");
		exit(1);
	}
}

void
drain_ring(GAsyncQueue * ring)
{
	g_async_queue_lock(ring);

	gpointer msg;
	while ((msg = g_async_queue_try_pop_unlocked(ring))) {
		free(msg);
	}
	g_async_queue_unlock(ring);
}

void
set_user_state(user_state_t state)
{
	int err;
	log_message(LOGT_APP, LOGL_TRACE, "snapfind: user is %s",
				state==USER_BUSY?"busy":"waiting");
	err = ls_set_user_state(shandle, state);
	if (err) {
		printf("failed to set user state: %d", err);
		exit(1);
	}
}

/*
 * This processes a message (command) from the interface
 * GUI to control the processing.
 */

void
handle_message(message_t * new_message)
{
	struct timezone tz;
	int				err;

	switch (new_message->type) {
		case START_SEARCH:

			/*
			 * delete old msgs
			 */
			drain_ring(from_search_thread);
			do_search((gid_list_t *) new_message->data, NULL);
			active = 1;
			search_active = 1;
			search_number++;
			err = gettimeofday(&search_start, &tz);
			assert(err == 0);
			break;

		case TERM_SEARCH:
			stop_search(new_message->data);
			search_active = 0;
			break;

		case DEFINE_SCOPE:
			define_scope(new_message->data);
			break;

			/*
			 * XXX get stats ???
			 */
		case SET_USER_BUSY:
			set_user_state(USER_BUSY);
			break;

		case SET_USER_WAITING:
			set_user_state(USER_WAITING);
			break;

		default:
			printf("XXX unknown message %d \n", new_message->type);
			assert(0);
			break;
	}
}

void
update_stats()
{
	int             num_dev;
	ls_dev_handle_t dev_list[SF_MAX_DEVICES];
	int             i, err, len;
	dev_stats_t    *dstats;
	int             tobj = 0, sobj = 0, dobj = 0;

	dstats = (dev_stats_t *) malloc(DEV_STATS_SIZE(SF_MAX_FILTERS));
	assert(dstats);

	num_dev = SF_MAX_DEVICES;

	err = ls_get_dev_list(shandle, dev_list, &num_dev);
	if (err != 0) {
		printf("update states: %d \n", err);
		exit(1);
	}

	for (i = 0; i < num_dev; i++) {
		len = DEV_STATS_SIZE(SF_MAX_FILTERS);
		err = ls_get_dev_stats(shandle, dev_list[i], dstats, &len);
		if (err) {
			printf("Failed to get dev stats \n");
			exit(1);
		}
		tobj += dstats->ds_objs_total;
		sobj += dstats->ds_objs_processed;
		dobj += dstats->ds_objs_dropped;
	}
	free(dstats);

	tobj_cnt = tobj;
	sobj_cnt = sobj;
	dobj_cnt = dobj;
}

/*
 * This is main function that is called thread interacting with the
 * search subsystem.
 */

void           *
sfind_search_main(void *foo)
{

	message_t      *message;
	ls_obj_handle_t cur_obj;
	int             err;
	int             temp;
	int		any;

	struct timespec timeout;

	sset = (search_set *)foo;

	/*
	 * XXX init_search();
	 */

	while (1) {
		any = 0;
		message = (message_t *) g_async_queue_try_pop(to_search_thread);
		if (message != NULL) {
			any = 1;
			handle_message(message);
			free(message);
		}
		if ((active) &&
			(g_async_queue_length(from_search_thread) < THUMBNAIL_DISPLAY_SIZE+1)) {
			err = ls_next_object(shandle, &cur_obj, LSEARCH_NO_BLOCK);
			if (err == ENOENT) {
				fprintf(stderr, "No more objects \n");  /* XXX */
				search_active = 0;
				active = 0;
				message = (message_t *) malloc(sizeof(*message));
				if (message == NULL) {
					fprintf(stderr, "non mem\n");
					exit(1);
				}
				message->type = DONE_OBJECTS;
				message->data = NULL;

				g_async_queue_push(from_search_thread, message);
			} else if ((err != 0) && (err != EWOULDBLOCK)) {
				/*
				 * XXX
				 */
				fprintf(stderr, "get_next_obj: failed on %d \n", err);
				exit(1);
			} else if (err == 0) {
				any = 1;
				message = (message_t *) malloc(sizeof(*message));
				assert(message != NULL);

				message->type = NEXT_OBJECT;
				message->data = cur_obj;
				g_async_queue_push(from_search_thread, message);
				astats.as_objs_queued++;
			}
		}
		err = ls_num_objects(shandle, &temp);
		temp += g_async_queue_length(from_search_thread);

		pend_obj_cnt = temp;
		update_stats();
		if (any == 0) {
			timeout.tv_sec = 0;
			timeout.tv_nsec = 100000000;    /* XXX 100ms ?? */
			nanosleep(&timeout, NULL);
		}
	}
	return (0);
}
<commit_msg>Make set_user_state failure non-fatal<commit_after>/*
 *  SnapFind
 *  An interactive image search application
 *  Version 1
 *
 *  Copyright (c) 2002-2005 Intel Corporation
 *  Copyright (c) 2007 Carnegie Mellon University
 *  All Rights Reserved.
 *
 *  This software is distributed under the terms of the Eclipse Public
 *  License, Version 1.0 which can be found in the file named LICENSE.
 *  ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS SOFTWARE CONSTITUTES
 *  RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
#include <sys/time.h>
#include <math.h>
#include <libgen.h>
#include <stdint.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>

#include "diamond_types.h"
#include "searchlet_api.h"
#include "lib_results.h"
#include "lib_sfimage.h"
#include "sf_consts.h"
#include "face_search.h"
#include "search_set.h"
#include "sfind_search.h"
#include "plugin.h"
#include "snapfind.h"

#include "lib_scope.h"

/*
 * this need to be global because we share it with the main
 * GUI.  XXX hack, do it right later.
 */
ls_search_handle_t shandle;
app_stats_t	astats;

/*
 * state the is global to all of these functions.
 */
/* XXX global for status window, fix  this someday */
int      search_active = 0;
static int     active  = 0;
int      search_number = 0;
struct timeval	search_start;

static search_set *sset = NULL;

/*
 * This initializes the search  state.
 */

void
init_search()
{
	shandle = ls_init_search();
	if (shandle == NULL) {
		printf("failed to initialize:  !! \n");
		exit(1);
	}
}

/*
 * This function initiates the search by building a filter
 * specification, setting the searchlet and then starting the search.
 */

void
do_search(gid_list_t * main_region, char *fspec)
{
	int             err;
	char           *filter_name;
	char           *dir_name;
	void 	       *cookie;
	search_iter_t iter;

	if (!fspec) {
		fspec = sset->build_filter_spec(NULL);
		if (fspec == NULL) {
			printf("failed to build filter specification \n");
			exit(1);
		}
	}

	dir_name = (char *) malloc(SF_MAX_PATH);
	if (dir_name == NULL) {
		exit(1);                /* XXX */
	}

	err = ls_set_searchlist(shandle, main_region->ngids,
				main_region->gids);
	if (err) {
		printf("Failed to set searchlist on  err %d \n", err);
		exit(1);
	}

	filter_name = first_searchlet_lib(&cookie);
	if (filter_name == NULL) {
		fprintf(stderr, "No filter libraries are defined \n");
		assert(0);
	}

	err = ls_set_searchlet(shandle, DEV_ISA_IA32, filter_name, fspec);
	if (err) {
		printf("Failed to set searchlet on err %d \n", err);
		exit(1);
	}
	free(filter_name);

	while ((filter_name = next_searchlet_lib(&cookie)) != NULL) {
		err = ls_add_filter_file(shandle, DEV_ISA_IA32, filter_name);
		free(filter_name);
	}

	/* Attach auxiliary data for this search.  */
	sset->write_blobs(shandle);

	/* reset application statistics */
	astats.as_objs_queued = 0;
	astats.as_objs_presented = 0;

	/* Go ahead and start the search.  */
	err = ls_start_search(shandle);
	if (err) {
		printf("Failed to start search on err %d \n", err);
		exit(1);
	}
}

/*
 *  Defines a scope for a new search.
 */
static void
define_scope(void *data)
{
	int             err;

	err = ls_define_scope();
	if (err != 0) {
		printf("XXX failed to define scope \n");
	}
}

/*
 *  Stops a currently executing search.
 */
static void
stop_search(void *data)
{
	int             err;

	static int		old_total = 0;

	astats.as_objs_presented = user_measurement.total_seen - old_total;
	old_total = user_measurement.total_seen;
	err = ls_terminate_search_extended(shandle, &astats);
	if (err != 0) {
		printf("XXX failed to terminate search \n");
		exit(1);
	}
}

void
drain_ring(GAsyncQueue * ring)
{
	g_async_queue_lock(ring);

	gpointer msg;
	while ((msg = g_async_queue_try_pop_unlocked(ring))) {
		free(msg);
	}
	g_async_queue_unlock(ring);
}

void
set_user_state(user_state_t state)
{
	int err;
	log_message(LOGT_APP, LOGL_TRACE, "snapfind: user is %s",
				state==USER_BUSY?"busy":"waiting");
	err = ls_set_user_state(shandle, state);
	if (err) {
		printf("failed to set user state: %d", err);
		//exit(1);
	}
}

/*
 * This processes a message (command) from the interface
 * GUI to control the processing.
 */

void
handle_message(message_t * new_message)
{
	struct timezone tz;
	int				err;

	switch (new_message->type) {
		case START_SEARCH:

			/*
			 * delete old msgs
			 */
			drain_ring(from_search_thread);
			do_search((gid_list_t *) new_message->data, NULL);
			active = 1;
			search_active = 1;
			search_number++;
			err = gettimeofday(&search_start, &tz);
			assert(err == 0);
			break;

		case TERM_SEARCH:
			stop_search(new_message->data);
			search_active = 0;
			break;

		case DEFINE_SCOPE:
			define_scope(new_message->data);
			break;

			/*
			 * XXX get stats ???
			 */
		case SET_USER_BUSY:
			set_user_state(USER_BUSY);
			break;

		case SET_USER_WAITING:
			set_user_state(USER_WAITING);
			break;

		default:
			printf("XXX unknown message %d \n", new_message->type);
			assert(0);
			break;
	}
}

void
update_stats()
{
	int             num_dev;
	ls_dev_handle_t dev_list[SF_MAX_DEVICES];
	int             i, err, len;
	dev_stats_t    *dstats;
	int             tobj = 0, sobj = 0, dobj = 0;

	dstats = (dev_stats_t *) malloc(DEV_STATS_SIZE(SF_MAX_FILTERS));
	assert(dstats);

	num_dev = SF_MAX_DEVICES;

	err = ls_get_dev_list(shandle, dev_list, &num_dev);
	if (err != 0) {
		printf("update states: %d \n", err);
		exit(1);
	}

	for (i = 0; i < num_dev; i++) {
		len = DEV_STATS_SIZE(SF_MAX_FILTERS);
		err = ls_get_dev_stats(shandle, dev_list[i], dstats, &len);
		if (err) {
			printf("Failed to get dev stats \n");
			exit(1);
		}
		tobj += dstats->ds_objs_total;
		sobj += dstats->ds_objs_processed;
		dobj += dstats->ds_objs_dropped;
	}
	free(dstats);

	tobj_cnt = tobj;
	sobj_cnt = sobj;
	dobj_cnt = dobj;
}

/*
 * This is main function that is called thread interacting with the
 * search subsystem.
 */

void           *
sfind_search_main(void *foo)
{

	message_t      *message;
	ls_obj_handle_t cur_obj;
	int             err;
	int             temp;
	int		any;

	struct timespec timeout;

	sset = (search_set *)foo;

	/*
	 * XXX init_search();
	 */

	while (1) {
		any = 0;
		message = (message_t *) g_async_queue_try_pop(to_search_thread);
		if (message != NULL) {
			any = 1;
			handle_message(message);
			free(message);
		}
		if ((active) &&
			(g_async_queue_length(from_search_thread) < THUMBNAIL_DISPLAY_SIZE+1)) {
			err = ls_next_object(shandle, &cur_obj, LSEARCH_NO_BLOCK);
			if (err == ENOENT) {
				fprintf(stderr, "No more objects \n");  /* XXX */
				search_active = 0;
				active = 0;
				message = (message_t *) malloc(sizeof(*message));
				if (message == NULL) {
					fprintf(stderr, "non mem\n");
					exit(1);
				}
				message->type = DONE_OBJECTS;
				message->data = NULL;

				g_async_queue_push(from_search_thread, message);
			} else if ((err != 0) && (err != EWOULDBLOCK)) {
				/*
				 * XXX
				 */
				fprintf(stderr, "get_next_obj: failed on %d \n", err);
				exit(1);
			} else if (err == 0) {
				any = 1;
				message = (message_t *) malloc(sizeof(*message));
				assert(message != NULL);

				message->type = NEXT_OBJECT;
				message->data = cur_obj;
				g_async_queue_push(from_search_thread, message);
				astats.as_objs_queued++;
			}
		}
		err = ls_num_objects(shandle, &temp);
		temp += g_async_queue_length(from_search_thread);

		pend_obj_cnt = temp;
		update_stats();
		if (any == 0) {
			timeout.tv_sec = 0;
			timeout.tv_nsec = 100000000;    /* XXX 100ms ?? */
			nanosleep(&timeout, NULL);
		}
	}
	return (0);
}
<|endoftext|>


<commit_before>#include "raytracer.h"

RayTracer::RayTracer( Camera &camera,
                      const Scene &scene,
                      const glm::vec3 background_color,
                      const size_t samples,
                      const size_t maximum_depth,
                      Buffer &buffer ) :
        camera_( camera ),
        scene_( scene ),
        background_color_{ background_color },
        samples_{ samples},
        maximum_depth_{ maximum_depth },
        buffer_( buffer )
{}

Ray RayTracer::get_new_ray( IntersectionRecord intersection_record )
{
    float r1 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
    float r2 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
    float theta = glm::acos( 1 - r1 );
    float phi = 2 * M_PI * r2;
    ONB onb_;

    onb_.setFromV(intersection_record.normal_);

    glm::vec3 cartesian_coordinate{ cosf(phi)*sinf(theta), cosf(theta), sinf(phi)*sinf(theta) };

    return Ray{ intersection_record.position_ + (intersection_record.normal_*0.001f), onb_.getBasisMatrix() * cartesian_coordinate };
}

Ray RayTracer::get_reflection(IntersectionRecord intersection_record, Ray ray)
{
    ONB onb_;

    onb_.setFromV(intersection_record.normal_);

    Ray newray;

    glm::vec3 newdir = glm::transpose(onb_.getBasisMatrix()) * ray.direction_;
    newdir = { newdir.x, -newdir.y, newdir.z };
    newray = { intersection_record.position_ + (intersection_record.normal_*0.001f), onb_.getBasisMatrix() * newdir };

    return newray;
}

double RayTracer::rSchlick1(const glm::vec3 normal, glm::vec3 incident, double n1, double n2)
{
    double r0 = (n1 - n2) /(n1 + n2);
    r0 *= r0;
    double cosX = -glm::dot(normal, incident);
    if (n1 > n2) {
        const double n = n1/n2;
        const double sinT2 = n * n * (1.0 - cosX * cosX);
        cosX = sqrt(1.0 - sinT2);
    }
    const double x = 1.0 - cosX;
    return r0 + ( 1.0 - r0 ) * x * x * x * x * x;
}

double RayTracer::rSchlick2(const glm::vec3 normal, glm::vec3 incident, double n1, double n2){

    double r0 = (n1 - n2) /(n1 + n2);
    r0 *= r0;
    double cosX = -glm::dot(normal, incident);
    if (n1 > n2) {
        const double n = n1/n2;
        const double sinT2 = n * n * (1.0 - cosX * cosX);
        if(sinT2 > 1.0) return 1.0;//TIR
        cosX = sqrt(1.0 - sinT2);
    }
    const double x = 1.0 - cosX;
    return r0 + ( 1.0 - r0 ) * x * x * x * x * x;
}

glm::dvec3 RayTracer::cook_torrance( glm::dvec3 wi, glm::dvec3 wo, IntersectionRecord intersection_record )
{
<<<<<<< HEAD
    glm::dvec3 h = glm::normalize( (wo - wi) / 2.0 );
    double nh  = glm::abs( glm::dot( glm::dvec3( intersection_record.normal_ ), h));
    double nwo = glm::abs( glm::dot( glm::dvec3( intersection_record.normal_ ), wo ));
    double nwi = glm::abs( glm::dot( glm::dvec3( intersection_record.normal_ ), -wi ));
    double hwo = glm::abs( glm::dot( h, wo ));
    double hwi = glm::abs( glm::dot( h, -wi ));
=======

    ONB tangent_frame;
                tangent_frame.setFromV( (glm::dvec3) intersection_record.normal_ );

                glm::dmat3x3 tangent_to_universe_space = tangent_frame.getBasisMatrix();
                glm::dmat3x3 universe_to_tangent_space = glm::transpose( tangent_to_universe_space );

    glm::dvec3 w_i = universe_to_tangent_space * (glm::dvec3)-wi;

    glm::dvec3 w_o = universe_to_tangent_space * (glm::dvec3)wo;

    glm::dvec3 h = glm::normalize((w_i + w_o));
    double nh  = glm::abs(  h.y );
    double nwo = glm::abs(  w_o.y );
    double nwi = glm::abs(  w_i.y );
    double hwo = glm::abs( glm::dot( h, w_o ));
    double hwi = glm::abs( glm::dot( h, w_i ));
>>>>>>> 79379bf16612739e6b8837579d91b5dacf6583c5

    //Beckmann

    double m = 0.35;
    double nh2 = nh * nh;
    double m2 = m * m;
    double d1 = 1.0 / ( M_PI * m2 * nh2 * nh2);
    double d2 = ( nh2 - 1.0 ) / (m2 * nh2 );
    double D = d1 * exp( d2 );

    //Geometric term

    double g1 = 2.0 * nh / hwi;
    double G = glm::min( 1.0, glm::min(g1 * nwo, g1 * nwi ));

    //Fresnel term

<<<<<<< HEAD
    double one_minus_hwi_5 = ( 1.0 - hwi ) * ( 1.0 - hwi ) * ( 1.0 - hwi ) * ( 1.0 - hwi ) * ( 1.0 - hwi );
    glm::dvec3 F = M_PI * glm::dvec3( intersection_record.brdf_ ) + ( glm::dvec3(1.0) - ( M_PI * glm::dvec3( intersection_record.brdf_ ) ) ) * one_minus_hwi_5;

=======
    double one_minus_hwi_5 = (1.0 - hwo) * (1.0 - hwo) * (1.0 - hwo) * (1.0 - hwo) * (1.0 - hwo);
    glm::dvec3 F = (M_PI)*(glm::dvec3)intersection_record.brdf_ + ( 1.0 -  (M_PI)*(glm::dvec3)intersection_record.brdf_) * one_minus_hwi_5;
    //printf("\n(%.2f, %.2f, %.2f)", F.x, F.y, F.z);
>>>>>>> 79379bf16612739e6b8837579d91b5dacf6583c5
    //Cook-Torrance

    return ( F * D * G) / ( 4.0 * nwo * nwi );
}

glm::vec3 RayTracer::L( Ray ray, IntersectionRecord intersection_record, size_t curr_depth ) //Rendering equation
{
    glm::vec3 Lo{ 0.0f, 0.0f, 0.0f };

    Ray refl_ray;

    intersection_record.t_ = std::numeric_limits< double >::max();

    if ( curr_depth < maximum_depth_ )
    {
        if ( scene_.intersect ( ray, intersection_record ))
        {
            if( intersection_record.pmirror_ )//if its a mirror
            {
                refl_ray = get_reflection(intersection_record, ray);

                Lo = L(refl_ray, intersection_record, ++curr_depth);

            }

            else if( intersection_record.glass_ )//if its glass
            {
                float n1, n2;

                if(glm::dot(ray.direction_,intersection_record.normal_)<0){//ENTRANDO NO VIDRO

                    n1 = 1.0f;
                    n2 = 2.0f;

                    double fresnel = rSchlick1(intersection_record.normal_, (ray.direction_), n1, n2);
                    double r = (double) (rand()) / (double) (RAND_MAX);

                    if(r<fresnel){
                        refl_ray = get_reflection(intersection_record, ray);
                        Lo = L(refl_ray, intersection_record, ++curr_depth);
                    }

                    else{
                        const float n = n1/n2;
                        const float cosI = -glm::dot(intersection_record.normal_, ray.direction_);
                        const double sinT2 = n * n * (1.0 - cosI * cosI);
                        const float cosT = glm::sqrt(1.0 - sinT2);

                        refl_ray.direction_ = glm::normalize( n * ray.direction_ + (n*cosI - cosT) * intersection_record.normal_);
                        refl_ray.origin_ = intersection_record.position_ + (0.001f*refl_ray.direction_);

                        Lo = L(refl_ray, intersection_record, ++curr_depth);
                    }
                }
                else{//SAINDO DO VIDRO
                    n1 = 2.0f;
                    n2 = 1.0f;

                    const float n = n1/n2;
                    double cosX = -glm::dot(intersection_record.normal_, ray.direction_);
                    const double sinT2 = n * n * (1.0 - cosX * cosX);

                    if(sinT2 > 1.0){
                        refl_ray = get_reflection(intersection_record, ray);
                        Lo = L(refl_ray, intersection_record, ++curr_depth);
                    }
                    else{
                        double fresnel = rSchlick2(intersection_record.normal_, (ray.direction_), n1, n2);
                        double r = (double) (rand()) / (double) (RAND_MAX+1.0);

                        if(r<fresnel){
                            refl_ray = get_reflection(intersection_record, ray);
                            Lo = L(refl_ray, intersection_record, ++curr_depth);
                        }
                        else{
                            const float n = n1/n2;
                            const float cosI = glm::dot(intersection_record.normal_, ray.direction_);
                            const double sinT2 = n * n * (1.0 - cosI * cosI);
                            const float cosT = glm::sqrt(1.0 - sinT2);

                            refl_ray.direction_ = glm::normalize(n * ray.direction_ + (n * cosI - cosT) * intersection_record.normal_);
                            refl_ray.origin_ = intersection_record.position_ + (0.001f*refl_ray.direction_);
                            Lo = L(refl_ray, intersection_record, ++curr_depth);
                        }
                    }
                }
            }

            else if( intersection_record.metal_ )//if its metal
            {
                refl_ray = get_new_ray( intersection_record );
                Lo = intersection_record.emittance_ + glm::vec3( cook_torrance( glm::dvec3( refl_ray.direction_ ), glm::dvec3( ray.direction_ ), intersection_record )) *
                L( refl_ray, intersection_record, ++curr_depth ) * glm::dot( intersection_record.normal_, refl_ray.direction_ );
            }

            else//if its diffuse
            {
                refl_ray = get_new_ray( intersection_record );

                Lo = intersection_record.emittance_ + 2.0f * ((float) M_PI) * intersection_record.brdf_ *
                L( refl_ray, intersection_record, ++curr_depth ) * glm::dot( intersection_record.normal_, refl_ray.direction_ );
            }
        }
    }
    return Lo;
}

void RayTracer::integrate( void )
{
    //Image space origin (i.e. x = 0 and y = 0) at the top left corner.

    Ray ray;
    IntersectionRecord intersection_record;

    #pragma omp parallel for schedule(dynamic, 1) private(ray, intersection_record)

    // Loops over image rows
    for ( std::size_t y = 0; y < buffer_.v_resolution_; y++ )
    {
        std::stringstream progress_stream;
        progress_stream << "\r  progress .........................: "
                        << std::fixed << std::setw( 6 )
                        << std::setprecision( 2 )
                        << 100.0 * y / ( buffer_.v_resolution_ - 1 )
                        << "%";

        std::clog << progress_stream.str();

        srand(std::time(0));

        // Loops over image columns
        for ( std::size_t x = 0; x < buffer_.h_resolution_; x++ )
        {
            for(std::size_t i = 0; i < samples_; i++ )
            {
                //intersection_record.t_ = std::numeric_limits< double >::max();

                float rand1 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
                float rand2 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);

                //Ray ray{ camera_.getWorldSpaceRay( glm::vec2{ x + 0.5f, y + 0.5f } ) };
                ray = { camera_.getWorldSpaceRay( glm::vec2{ x + rand1, y + rand2 } ) };

                //if ( scene_.intersect( ray, intersection_record ) )
                //buffer_.buffer_data_[x][y] = glm::vec3{ intersection_record.t_ * 0.2f };
                //final_color = final_color + intersection_record.color_;
                buffer_.buffer_data_[x][y] += L( ray, intersection_record, 0 );
            }
            buffer_.buffer_data_[x][y] /= static_cast <float> (samples_);
        }
    }

    std::clog << std::endl;
}

<commit_msg>Fixed failed merge<commit_after>#include "raytracer.h"

RayTracer::RayTracer( Camera &camera,
                      const Scene &scene,
                      const glm::vec3 background_color,
                      const size_t samples,
                      const size_t maximum_depth,
                      Buffer &buffer ) :
        camera_( camera ),
        scene_( scene ),
        background_color_{ background_color },
        samples_{ samples},
        maximum_depth_{ maximum_depth },
        buffer_( buffer )
{}

Ray RayTracer::get_new_ray( IntersectionRecord intersection_record )
{
    float r1 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
    float r2 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
    float theta = glm::acos( 1 - r1 );
    float phi = 2 * M_PI * r2;
    ONB onb_;

    onb_.setFromV(intersection_record.normal_);

    glm::vec3 cartesian_coordinate{ cosf(phi)*sinf(theta), cosf(theta), sinf(phi)*sinf(theta) };

    return Ray{ intersection_record.position_ + (intersection_record.normal_*0.001f), onb_.getBasisMatrix() * cartesian_coordinate };
}

Ray RayTracer::get_reflection(IntersectionRecord intersection_record, Ray ray)
{
    ONB onb_;

    onb_.setFromV(intersection_record.normal_);

    Ray newray;

    glm::vec3 newdir = glm::transpose(onb_.getBasisMatrix()) * ray.direction_;
    newdir = { newdir.x, -newdir.y, newdir.z };
    newray = { intersection_record.position_ + (intersection_record.normal_*0.001f), onb_.getBasisMatrix() * newdir };

    return newray;
}

double RayTracer::rSchlick1(const glm::vec3 normal, glm::vec3 incident, double n1, double n2)
{
    double r0 = (n1 - n2) /(n1 + n2);
    r0 *= r0;
    double cosX = -glm::dot(normal, incident);
    if (n1 > n2) {
        const double n = n1/n2;
        const double sinT2 = n * n * (1.0 - cosX * cosX);
        cosX = sqrt(1.0 - sinT2);
    }
    const double x = 1.0 - cosX;
    return r0 + ( 1.0 - r0 ) * x * x * x * x * x;
}

double RayTracer::rSchlick2(const glm::vec3 normal, glm::vec3 incident, double n1, double n2){

    double r0 = (n1 - n2) /(n1 + n2);
    r0 *= r0;
    double cosX = -glm::dot(normal, incident);
    if (n1 > n2) {
        const double n = n1/n2;
        const double sinT2 = n * n * (1.0 - cosX * cosX);
        if(sinT2 > 1.0) return 1.0;//TIR
        cosX = sqrt(1.0 - sinT2);
    }
    const double x = 1.0 - cosX;
    return r0 + ( 1.0 - r0 ) * x * x * x * x * x;
}

glm::dvec3 RayTracer::cook_torrance( glm::dvec3 wi, glm::dvec3 wo, IntersectionRecord intersection_record )
{
    glm::dvec3 h = glm::normalize( (wo - wi) / 2.0 );
    double nh  = glm::abs( glm::dot( glm::dvec3( intersection_record.normal_ ), h));
    double nwo = glm::abs( glm::dot( glm::dvec3( intersection_record.normal_ ), wo ));
    double nwi = glm::abs( glm::dot( glm::dvec3( intersection_record.normal_ ), -wi ));
    double hwo = glm::abs( glm::dot( h, wo ));
    double hwi = glm::abs( glm::dot( h, -wi ));

    //Beckmann

    double m = 0.35;
    double nh2 = nh * nh;
    double m2 = m * m;
    double d1 = 1.0 / ( M_PI * m2 * nh2 * nh2);
    double d2 = ( nh2 - 1.0 ) / (m2 * nh2 );
    double D = d1 * glm::exp( d2 );

    //Geometric term

    double g1 = 2.0 * nh / hwo;
    double G = glm::min( 1.0, glm::min(g1 * nwo, g1 * nwi ));

    //Fresnel term

    double one_minus_hwi_5 = ( 1.0 - hwi ) * ( 1.0 - hwi ) * ( 1.0 - hwi ) * ( 1.0 - hwi ) * ( 1.0 - hwi );
    glm::dvec3 F = M_PI * glm::dvec3( intersection_record.brdf_ ) + ( glm::dvec3(1.0) - ( M_PI * glm::dvec3( intersection_record.brdf_ ) ) ) * one_minus_hwi_5;

    //Cook-Torrance

    return ( F * D * G) / ( 4.0 * nwo * nwi );
}

glm::vec3 RayTracer::L( Ray ray, IntersectionRecord intersection_record, size_t curr_depth ) //Rendering equation
{
    glm::vec3 Lo{ 0.0f, 0.0f, 0.0f };

    Ray refl_ray;

    intersection_record.t_ = std::numeric_limits< double >::max();

    if ( curr_depth < maximum_depth_ )
    {
        if ( scene_.intersect ( ray, intersection_record ))
        {
            if( intersection_record.pmirror_ )//if its a mirror
            {
                refl_ray = get_reflection(intersection_record, ray);

                Lo = L(refl_ray, intersection_record, ++curr_depth);

            }

            else if( intersection_record.glass_ )//if its glass
            {
                float n1, n2;

                if(glm::dot(ray.direction_,intersection_record.normal_)<0){//ENTRANDO NO VIDRO

                    n1 = 1.0f;
                    n2 = 2.0f;

                    double fresnel = rSchlick1(intersection_record.normal_, (ray.direction_), n1, n2);
                    double r = (double) (rand()) / (double) (RAND_MAX);

                    if(r<fresnel){
                        refl_ray = get_reflection(intersection_record, ray);
                        Lo = L(refl_ray, intersection_record, ++curr_depth);
                    }

                    else{
                        const float n = n1/n2;
                        const float cosI = -glm::dot(intersection_record.normal_, ray.direction_);
                        const double sinT2 = n * n * (1.0 - cosI * cosI);
                        const float cosT = glm::sqrt(1.0 - sinT2);

                        refl_ray.direction_ = glm::normalize( n * ray.direction_ + (n*cosI - cosT) * intersection_record.normal_);
                        refl_ray.origin_ = intersection_record.position_ + (0.001f*refl_ray.direction_);

                        Lo = L(refl_ray, intersection_record, ++curr_depth);
                    }
                }
                else{//SAINDO DO VIDRO
                    n1 = 2.0f;
                    n2 = 1.0f;

                    const float n = n1/n2;
                    double cosX = -glm::dot(intersection_record.normal_, ray.direction_);
                    const double sinT2 = n * n * (1.0 - cosX * cosX);

                    if(sinT2 > 1.0){
                        refl_ray = get_reflection(intersection_record, ray);
                        Lo = L(refl_ray, intersection_record, ++curr_depth);
                    }
                    else{
                        double fresnel = rSchlick2(intersection_record.normal_, (ray.direction_), n1, n2);
                        double r = (double) (rand()) / (double) (RAND_MAX+1.0);

                        if(r<fresnel){
                            refl_ray = get_reflection(intersection_record, ray);
                            Lo = L(refl_ray, intersection_record, ++curr_depth);
                        }
                        else{
                            const float n = n1/n2;
                            const float cosI = glm::dot(intersection_record.normal_, ray.direction_);
                            const double sinT2 = n * n * (1.0 - cosI * cosI);
                            const float cosT = glm::sqrt(1.0 - sinT2);

                            refl_ray.direction_ = glm::normalize(n * ray.direction_ + (n * cosI - cosT) * intersection_record.normal_);
                            refl_ray.origin_ = intersection_record.position_ + (0.001f*refl_ray.direction_);
                            Lo = L(refl_ray, intersection_record, ++curr_depth);
                        }
                    }
                }
            }

            else if( intersection_record.metal_ )//if its metal
            {
                refl_ray = get_new_ray( intersection_record );
                Lo = intersection_record.emittance_ + glm::vec3( cook_torrance( glm::dvec3( refl_ray.direction_ ), glm::dvec3( ray.direction_ ), intersection_record )) *
                L( refl_ray, intersection_record, ++curr_depth ) * glm::dot( intersection_record.normal_, refl_ray.direction_ );
            }

            else//if its diffuse
            {
                refl_ray = get_new_ray( intersection_record );

                Lo = intersection_record.emittance_ + 2.0f * ((float) M_PI) * intersection_record.brdf_ *
                L( refl_ray, intersection_record, ++curr_depth ) * glm::dot( intersection_record.normal_, refl_ray.direction_ );
            }
        }
    }
    return Lo;
}

void RayTracer::integrate( void )
{
    //Image space origin (i.e. x = 0 and y = 0) at the top left corner.

    Ray ray;
    IntersectionRecord intersection_record;

    #pragma omp parallel for schedule(dynamic, 1) private(ray, intersection_record)

    // Loops over image rows
    for ( std::size_t y = 0; y < buffer_.v_resolution_; y++ )
    {
        std::stringstream progress_stream;
        progress_stream << "\r  progress .........................: "
                        << std::fixed << std::setw( 6 )
                        << std::setprecision( 2 )
                        << 100.0 * y / ( buffer_.v_resolution_ - 1 )
                        << "%";

        std::clog << progress_stream.str();

        srand(std::time(0));

        // Loops over image columns
        for ( std::size_t x = 0; x < buffer_.h_resolution_; x++ )
        {
            for(std::size_t i = 0; i < samples_; i++ )
            {
                //intersection_record.t_ = std::numeric_limits< double >::max();

                float rand1 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
                float rand2 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);

                //Ray ray{ camera_.getWorldSpaceRay( glm::vec2{ x + 0.5f, y + 0.5f } ) };
                ray = { camera_.getWorldSpaceRay( glm::vec2{ x + rand1, y + rand2 } ) };

                //if ( scene_.intersect( ray, intersection_record ) )
                //buffer_.buffer_data_[x][y] = glm::vec3{ intersection_record.t_ * 0.2f };
                //final_color = final_color + intersection_record.color_;
                buffer_.buffer_data_[x][y] += L( ray, intersection_record, 0 );
            }
            buffer_.buffer_data_[x][y] /= static_cast <float> (samples_);
        }
    }

    std::clog << std::endl;
}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Original authors — credit is appreciated but not required:

        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 —
            Vladimír Vondruš <mosra@centrum.cz>
        2018 — scturtle <scturtle@gmail.com>

    This is free and unencumbered software released into the public domain.

    Anyone is free to copy, modify, publish, use, compile, sell, or distribute
    this software, either in source code form or as a compiled binary, for any
    purpose, commercial or non-commercial, and by any means.

    In jurisdictions that recognize copyright laws, the author or authors of
    this software dedicate any and all copyright interest in the software to
    the public domain. We make this dedication for the benefit of the public
    at large and to the detriment of our heirs and successors. We intend this
    dedication to be an overt act of relinquishment in perpetuity of all
    present and future rights to this software under copyright law.

    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 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 <Magnum/Image.h>
#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/GL/PixelFormat.h>
#include <Magnum/GL/Renderer.h>
#include <Magnum/MeshTools/Compile.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Primitives/Grid.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/MatrixTransformation3D.h>
#include <Magnum/SceneGraph/Object.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/Shaders/Flat.h>
#include <Magnum/Shaders/VertexColor.h>
#include <Magnum/Trade/MeshData3D.h>

namespace Magnum { namespace Examples {

using Object3D = SceneGraph::Object<SceneGraph::MatrixTransformation3D>;
using Scene3D = SceneGraph::Scene<SceneGraph::MatrixTransformation3D>;

using namespace Math::Literals;

class MouseInteractionExample: public Platform::Application {
    public:
        explicit MouseInteractionExample(const Arguments& arguments);

    private:
        Float depthAt(const Vector2i& position);
        Vector3 unproject(const Vector2i& position, Float depth) const;

        void keyPressEvent(KeyEvent& event) override;
        void mousePressEvent(MouseEvent& event) override;
        void mouseMoveEvent(MouseMoveEvent& event) override;
        void mouseScrollEvent(MouseScrollEvent& event) override;
        void drawEvent() override;

        Shaders::VertexColor3D _vertexColorShader{NoCreate};
        Shaders::Flat3D _flatShader{NoCreate};
        GL::Mesh _mesh{NoCreate}, _grid{NoCreate};

        Scene3D _scene;
        SceneGraph::DrawableGroup3D _drawables;
        Object3D* _cameraObject;
        SceneGraph::Camera3D* _camera;

        Float _lastDepth;
        Vector2i _lastPosition{-1};
        Vector3 _rotationPoint, _translationPoint;
};

class VertexColorDrawable: public SceneGraph::Drawable3D {
    public:
        explicit VertexColorDrawable(Object3D& object, Shaders::VertexColor3D& shader, GL::Mesh& mesh, SceneGraph::DrawableGroup3D& drawables): SceneGraph::Drawable3D{object, &drawables}, _shader(shader), _mesh(mesh) {}

        void draw(const Matrix4& transformation, SceneGraph::Camera3D& camera) {
            _shader.setTransformationProjectionMatrix(camera.projectionMatrix()*transformation);
            _mesh.draw(_shader);
        }

    private:
        Shaders::VertexColor3D& _shader;
        GL::Mesh& _mesh;
};

class FlatDrawable: public SceneGraph::Drawable3D {
    public:
        explicit FlatDrawable(Object3D& object, Shaders::Flat3D& shader, GL::Mesh& mesh, SceneGraph::DrawableGroup3D& drawables): SceneGraph::Drawable3D{object, &drawables}, _shader(shader), _mesh(mesh) {}

        void draw(const Matrix4& transformation, SceneGraph::Camera3D& camera) {
            _shader.setColor(0x747474_rgbf)
                .setTransformationProjectionMatrix(camera.projectionMatrix()*transformation);
            _mesh.draw(_shader);
        }

    private:
        Shaders::Flat3D& _shader;
        GL::Mesh& _mesh;
};

MouseInteractionExample::MouseInteractionExample(const Arguments& arguments): Platform::Application{arguments, NoCreate} {
    /* Try 8x MSAA, fall back to zero samples if not possible. Enable only 2x
       MSAA if we have enough DPI. */
    {
        const Vector2 dpiScaling = this->dpiScaling({});
        Configuration conf;
        conf.setTitle("Magnum Mouse Interaction Example")
            .setSize(conf.size(), dpiScaling);
        GLConfiguration glConf;
        glConf.setSampleCount(dpiScaling.max() < 2.0f ? 8 : 2);
        if(!tryCreate(conf, glConf))
            create(conf, glConf.setSampleCount(0));
    }

    /* Shaders, renderer setup */
    _vertexColorShader = Shaders::VertexColor3D{};
    _flatShader = Shaders::Flat3D{};
    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);

    /* Triangle data */
    const struct {
        Vector3 pos;
        Color3 color;
    } data[]{{{-1.0f, -1.0f, 0.0f}, 0xff0000_rgbf},
             {{ 1.0f, -1.0f, 0.0f}, 0x00ff00_rgbf},
             {{ 0.0f,  1.0f, 0.0f}, 0x0000ff_rgbf}};

    /* Triangle mesh */
    GL::Buffer buffer;
    buffer.setData(data);
    _mesh = GL::Mesh{};
    _mesh.setCount(3)
        .addVertexBuffer(std::move(buffer), 0,
            Shaders::VertexColor3D::Position{},
            Shaders::VertexColor3D::Color3{});

    /* Triangle object */
    auto triangle = new Object3D{&_scene};
    new VertexColorDrawable{*triangle, _vertexColorShader, _mesh, _drawables};

    /* Grid */
    _grid = MeshTools::compile(Primitives::grid3DWireframe({15, 15}));
    auto grid = new Object3D{&_scene};
    (*grid)
        .rotateX(90.0_degf)
        .scale(Vector3{8.0f});
    new FlatDrawable{*grid, _flatShader, _grid, _drawables};

    /* Set up the camera */
    _cameraObject = new Object3D{&_scene};
    (*_cameraObject)
        .translate(Vector3::zAxis(5.0f))
        .rotateX(-15.0_degf)
        .rotateY(30.0_degf);
    _camera = new SceneGraph::Camera3D{*_cameraObject};
    _camera->setProjectionMatrix(Matrix4::perspectiveProjection(
        45.0_degf, Vector2{windowSize()}.aspectRatio(), 0.01f, 100.0f));

    /* Initialize initial depth to the value at scene center */
    _lastDepth = ((_camera->projectionMatrix()*_camera->cameraMatrix()).transformPoint({}).z() + 1.0f)*0.5f;
}

Float MouseInteractionExample::depthAt(const Vector2i& position) {
    const Vector2i fbPosition{position.x(), GL::defaultFramebuffer.viewport().sizeY() - position.y() - 1};

    GL::defaultFramebuffer.mapForRead(GL::DefaultFramebuffer::ReadAttachment::Front);
    Image2D data = GL::defaultFramebuffer.read(
        Range2Di::fromSize(fbPosition, Vector2i{1}).padded(Vector2i{2}),
        {GL::PixelFormat::DepthComponent, GL::PixelType::Float});

    return Math::min(Containers::arrayCast<const Float>(data.data()));
}

Vector3 MouseInteractionExample::unproject(const Vector2i& position, Float depth) const {
    const Range2Di view = GL::defaultFramebuffer.viewport();
    const Vector2i fbPosition{position.x(), view.sizeY() - position.y() - 1};
    const Vector3 in{2*Vector2{fbPosition - view.min()}/Vector2{view.size()} - Vector2{1.0f}, depth*2.0f - 1.0f};

    /*
        Use the following to get global coordinates instead of camera-relative:

        (_cameraObject->absoluteTransformationMatrix()*_camera->projectionMatrix().inverted()).transformPoint(in)
    */
    return _camera->projectionMatrix().inverted().transformPoint(in);
}

void MouseInteractionExample::keyPressEvent(KeyEvent& event) {
    /* Reset the transformation to the original view */
    if(event.key() == KeyEvent::Key::NumZero) {
        (*_cameraObject)
            .resetTransformation()
            .translate(Vector3::zAxis(5.0f))
            .rotateX(-15.0_degf)
            .rotateY(30.0_degf);
        redraw();
        return;

    /* Axis-aligned view */
    } else if(event.key() == KeyEvent::Key::NumOne ||
              event.key() == KeyEvent::Key::NumThree ||
              event.key() == KeyEvent::Key::NumSeven)
    {
        /* Start with current camera translation with the rotation inverted */
        const Vector3 viewTranslation = _cameraObject->transformation().rotationScaling().inverted()*_cameraObject->transformation().translation();

        /* Front/back */
        const Float multiplier = event.modifiers() & KeyEvent::Modifier::Ctrl ? -1.0f : 1.0f;

        Matrix4 transformation;
        if(event.key() == KeyEvent::Key::NumSeven) /* Top/bottom */
            transformation = Matrix4::rotationX(-90.0_degf*multiplier);
        else if(event.key() == KeyEvent::Key::NumOne) /* Front/back */
            transformation = Matrix4::rotationY(90.0_degf - 90.0_degf*multiplier);
        else if(event.key() == KeyEvent::Key::NumThree) /* Right/left */
            transformation = Matrix4::rotationY(90.0_degf*multiplier);
        else CORRADE_ASSERT_UNREACHABLE();

        _cameraObject->setTransformation(transformation*Matrix4::translation(viewTranslation));
        redraw();
    }
}

void MouseInteractionExample::mousePressEvent(MouseEvent& event) {
    /* Due to compatibility reasons, scroll is also reported as a press event,
       so filter that out. Could be removed once MouseEvent::Button::Wheel is
       gone from Magnum. */
    if(event.button() != MouseEvent::Button::Left &&
       event.button() != MouseEvent::Button::Middle)
        return;

    const Float currentDepth = depthAt(event.position());
    const Float depth = currentDepth == 1.0f ? _lastDepth : currentDepth;
    _translationPoint = unproject(event.position(), depth);
    /* Update the rotation point only if we're not zooming against infinite
       depth or if the original rotation point is not yet initialized */
    if(currentDepth != 1.0f || _rotationPoint.isZero()) {
        _rotationPoint = _translationPoint;
        _lastDepth = depth;
    }
}

void MouseInteractionExample::mouseMoveEvent(MouseMoveEvent& event) {
    if(_lastPosition == Vector2i{-1}) _lastPosition = event.position();
    const Vector2i delta = event.position() - _lastPosition;
    _lastPosition = event.position();

    if(!event.buttons()) return;

    /* Translate */
    if(event.modifiers() & MouseMoveEvent::Modifier::Shift) {
        const Vector3 p = unproject(event.position(), _lastDepth);
        _cameraObject->translateLocal(_translationPoint - p); /* is Z always 0? */
        _translationPoint = p;

    /* Rotate around rotation point */
    } else _cameraObject->transformLocal(
        Matrix4::translation(_rotationPoint)*
        Matrix4::rotationX(-0.01_radf*delta.y())*
        Matrix4::rotationY(-0.01_radf*delta.x())*
        Matrix4::translation(-_rotationPoint));

    redraw();
}

void MouseInteractionExample::mouseScrollEvent(MouseScrollEvent& event) {
    const Float currentDepth = depthAt(event.position());
    const Float depth = currentDepth == 1.0f ? _lastDepth : currentDepth;
    const Vector3 p = unproject(event.position(), depth);
    /* Update the rotation point only if we're not zooming against infinite
       depth or if the original rotation point is not yet initialized */
    if(currentDepth != 1.0f || _rotationPoint.isZero()) {
        _rotationPoint = p;
        _lastDepth = depth;
    }

    const Int direction = event.offset().y();
    if(!direction) return;

    /* Move towards/backwards the rotation point in cam coords */
    _cameraObject->translateLocal(_rotationPoint*(direction < 0 ? -1.0f : 1.0f)*0.1f);

    redraw();
}

void MouseInteractionExample::drawEvent() {
    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth);

    _camera->draw(_drawables);

    swapBuffers();
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::MouseInteractionExample)
<commit_msg>mouseinteraction: fix build without deprecated APIs.<commit_after>/*
    This file is part of Magnum.

    Original authors — credit is appreciated but not required:

        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 —
            Vladimír Vondruš <mosra@centrum.cz>
        2018 — scturtle <scturtle@gmail.com>

    This is free and unencumbered software released into the public domain.

    Anyone is free to copy, modify, publish, use, compile, sell, or distribute
    this software, either in source code form or as a compiled binary, for any
    purpose, commercial or non-commercial, and by any means.

    In jurisdictions that recognize copyright laws, the author or authors of
    this software dedicate any and all copyright interest in the software to
    the public domain. We make this dedication for the benefit of the public
    at large and to the detriment of our heirs and successors. We intend this
    dedication to be an overt act of relinquishment in perpetuity of all
    present and future rights to this software under copyright law.

    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 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 <Magnum/Image.h>
#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/GL/PixelFormat.h>
#include <Magnum/GL/Renderer.h>
#include <Magnum/Math/FunctionsBatch.h>
#include <Magnum/MeshTools/Compile.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Primitives/Grid.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/MatrixTransformation3D.h>
#include <Magnum/SceneGraph/Object.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/Shaders/Flat.h>
#include <Magnum/Shaders/VertexColor.h>
#include <Magnum/Trade/MeshData3D.h>

namespace Magnum { namespace Examples {

using Object3D = SceneGraph::Object<SceneGraph::MatrixTransformation3D>;
using Scene3D = SceneGraph::Scene<SceneGraph::MatrixTransformation3D>;

using namespace Math::Literals;

class MouseInteractionExample: public Platform::Application {
    public:
        explicit MouseInteractionExample(const Arguments& arguments);

    private:
        Float depthAt(const Vector2i& position);
        Vector3 unproject(const Vector2i& position, Float depth) const;

        void keyPressEvent(KeyEvent& event) override;
        void mousePressEvent(MouseEvent& event) override;
        void mouseMoveEvent(MouseMoveEvent& event) override;
        void mouseScrollEvent(MouseScrollEvent& event) override;
        void drawEvent() override;

        Shaders::VertexColor3D _vertexColorShader{NoCreate};
        Shaders::Flat3D _flatShader{NoCreate};
        GL::Mesh _mesh{NoCreate}, _grid{NoCreate};

        Scene3D _scene;
        SceneGraph::DrawableGroup3D _drawables;
        Object3D* _cameraObject;
        SceneGraph::Camera3D* _camera;

        Float _lastDepth;
        Vector2i _lastPosition{-1};
        Vector3 _rotationPoint, _translationPoint;
};

class VertexColorDrawable: public SceneGraph::Drawable3D {
    public:
        explicit VertexColorDrawable(Object3D& object, Shaders::VertexColor3D& shader, GL::Mesh& mesh, SceneGraph::DrawableGroup3D& drawables): SceneGraph::Drawable3D{object, &drawables}, _shader(shader), _mesh(mesh) {}

        void draw(const Matrix4& transformation, SceneGraph::Camera3D& camera) {
            _shader.setTransformationProjectionMatrix(camera.projectionMatrix()*transformation);
            _mesh.draw(_shader);
        }

    private:
        Shaders::VertexColor3D& _shader;
        GL::Mesh& _mesh;
};

class FlatDrawable: public SceneGraph::Drawable3D {
    public:
        explicit FlatDrawable(Object3D& object, Shaders::Flat3D& shader, GL::Mesh& mesh, SceneGraph::DrawableGroup3D& drawables): SceneGraph::Drawable3D{object, &drawables}, _shader(shader), _mesh(mesh) {}

        void draw(const Matrix4& transformation, SceneGraph::Camera3D& camera) {
            _shader.setColor(0x747474_rgbf)
                .setTransformationProjectionMatrix(camera.projectionMatrix()*transformation);
            _mesh.draw(_shader);
        }

    private:
        Shaders::Flat3D& _shader;
        GL::Mesh& _mesh;
};

MouseInteractionExample::MouseInteractionExample(const Arguments& arguments): Platform::Application{arguments, NoCreate} {
    /* Try 8x MSAA, fall back to zero samples if not possible. Enable only 2x
       MSAA if we have enough DPI. */
    {
        const Vector2 dpiScaling = this->dpiScaling({});
        Configuration conf;
        conf.setTitle("Magnum Mouse Interaction Example")
            .setSize(conf.size(), dpiScaling);
        GLConfiguration glConf;
        glConf.setSampleCount(dpiScaling.max() < 2.0f ? 8 : 2);
        if(!tryCreate(conf, glConf))
            create(conf, glConf.setSampleCount(0));
    }

    /* Shaders, renderer setup */
    _vertexColorShader = Shaders::VertexColor3D{};
    _flatShader = Shaders::Flat3D{};
    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);

    /* Triangle data */
    const struct {
        Vector3 pos;
        Color3 color;
    } data[]{{{-1.0f, -1.0f, 0.0f}, 0xff0000_rgbf},
             {{ 1.0f, -1.0f, 0.0f}, 0x00ff00_rgbf},
             {{ 0.0f,  1.0f, 0.0f}, 0x0000ff_rgbf}};

    /* Triangle mesh */
    GL::Buffer buffer;
    buffer.setData(data);
    _mesh = GL::Mesh{};
    _mesh.setCount(3)
        .addVertexBuffer(std::move(buffer), 0,
            Shaders::VertexColor3D::Position{},
            Shaders::VertexColor3D::Color3{});

    /* Triangle object */
    auto triangle = new Object3D{&_scene};
    new VertexColorDrawable{*triangle, _vertexColorShader, _mesh, _drawables};

    /* Grid */
    _grid = MeshTools::compile(Primitives::grid3DWireframe({15, 15}));
    auto grid = new Object3D{&_scene};
    (*grid)
        .rotateX(90.0_degf)
        .scale(Vector3{8.0f});
    new FlatDrawable{*grid, _flatShader, _grid, _drawables};

    /* Set up the camera */
    _cameraObject = new Object3D{&_scene};
    (*_cameraObject)
        .translate(Vector3::zAxis(5.0f))
        .rotateX(-15.0_degf)
        .rotateY(30.0_degf);
    _camera = new SceneGraph::Camera3D{*_cameraObject};
    _camera->setProjectionMatrix(Matrix4::perspectiveProjection(
        45.0_degf, Vector2{windowSize()}.aspectRatio(), 0.01f, 100.0f));

    /* Initialize initial depth to the value at scene center */
    _lastDepth = ((_camera->projectionMatrix()*_camera->cameraMatrix()).transformPoint({}).z() + 1.0f)*0.5f;
}

Float MouseInteractionExample::depthAt(const Vector2i& position) {
    const Vector2i fbPosition{position.x(), GL::defaultFramebuffer.viewport().sizeY() - position.y() - 1};

    GL::defaultFramebuffer.mapForRead(GL::DefaultFramebuffer::ReadAttachment::Front);
    Image2D data = GL::defaultFramebuffer.read(
        Range2Di::fromSize(fbPosition, Vector2i{1}).padded(Vector2i{2}),
        {GL::PixelFormat::DepthComponent, GL::PixelType::Float});

    return Math::min(Containers::arrayCast<const Float>(data.data()));
}

Vector3 MouseInteractionExample::unproject(const Vector2i& position, Float depth) const {
    const Range2Di view = GL::defaultFramebuffer.viewport();
    const Vector2i fbPosition{position.x(), view.sizeY() - position.y() - 1};
    const Vector3 in{2*Vector2{fbPosition - view.min()}/Vector2{view.size()} - Vector2{1.0f}, depth*2.0f - 1.0f};

    /*
        Use the following to get global coordinates instead of camera-relative:

        (_cameraObject->absoluteTransformationMatrix()*_camera->projectionMatrix().inverted()).transformPoint(in)
    */
    return _camera->projectionMatrix().inverted().transformPoint(in);
}

void MouseInteractionExample::keyPressEvent(KeyEvent& event) {
    /* Reset the transformation to the original view */
    if(event.key() == KeyEvent::Key::NumZero) {
        (*_cameraObject)
            .resetTransformation()
            .translate(Vector3::zAxis(5.0f))
            .rotateX(-15.0_degf)
            .rotateY(30.0_degf);
        redraw();
        return;

    /* Axis-aligned view */
    } else if(event.key() == KeyEvent::Key::NumOne ||
              event.key() == KeyEvent::Key::NumThree ||
              event.key() == KeyEvent::Key::NumSeven)
    {
        /* Start with current camera translation with the rotation inverted */
        const Vector3 viewTranslation = _cameraObject->transformation().rotationScaling().inverted()*_cameraObject->transformation().translation();

        /* Front/back */
        const Float multiplier = event.modifiers() & KeyEvent::Modifier::Ctrl ? -1.0f : 1.0f;

        Matrix4 transformation;
        if(event.key() == KeyEvent::Key::NumSeven) /* Top/bottom */
            transformation = Matrix4::rotationX(-90.0_degf*multiplier);
        else if(event.key() == KeyEvent::Key::NumOne) /* Front/back */
            transformation = Matrix4::rotationY(90.0_degf - 90.0_degf*multiplier);
        else if(event.key() == KeyEvent::Key::NumThree) /* Right/left */
            transformation = Matrix4::rotationY(90.0_degf*multiplier);
        else CORRADE_ASSERT_UNREACHABLE();

        _cameraObject->setTransformation(transformation*Matrix4::translation(viewTranslation));
        redraw();
    }
}

void MouseInteractionExample::mousePressEvent(MouseEvent& event) {
    /* Due to compatibility reasons, scroll is also reported as a press event,
       so filter that out. Could be removed once MouseEvent::Button::Wheel is
       gone from Magnum. */
    if(event.button() != MouseEvent::Button::Left &&
       event.button() != MouseEvent::Button::Middle)
        return;

    const Float currentDepth = depthAt(event.position());
    const Float depth = currentDepth == 1.0f ? _lastDepth : currentDepth;
    _translationPoint = unproject(event.position(), depth);
    /* Update the rotation point only if we're not zooming against infinite
       depth or if the original rotation point is not yet initialized */
    if(currentDepth != 1.0f || _rotationPoint.isZero()) {
        _rotationPoint = _translationPoint;
        _lastDepth = depth;
    }
}

void MouseInteractionExample::mouseMoveEvent(MouseMoveEvent& event) {
    if(_lastPosition == Vector2i{-1}) _lastPosition = event.position();
    const Vector2i delta = event.position() - _lastPosition;
    _lastPosition = event.position();

    if(!event.buttons()) return;

    /* Translate */
    if(event.modifiers() & MouseMoveEvent::Modifier::Shift) {
        const Vector3 p = unproject(event.position(), _lastDepth);
        _cameraObject->translateLocal(_translationPoint - p); /* is Z always 0? */
        _translationPoint = p;

    /* Rotate around rotation point */
    } else _cameraObject->transformLocal(
        Matrix4::translation(_rotationPoint)*
        Matrix4::rotationX(-0.01_radf*delta.y())*
        Matrix4::rotationY(-0.01_radf*delta.x())*
        Matrix4::translation(-_rotationPoint));

    redraw();
}

void MouseInteractionExample::mouseScrollEvent(MouseScrollEvent& event) {
    const Float currentDepth = depthAt(event.position());
    const Float depth = currentDepth == 1.0f ? _lastDepth : currentDepth;
    const Vector3 p = unproject(event.position(), depth);
    /* Update the rotation point only if we're not zooming against infinite
       depth or if the original rotation point is not yet initialized */
    if(currentDepth != 1.0f || _rotationPoint.isZero()) {
        _rotationPoint = p;
        _lastDepth = depth;
    }

    const Int direction = event.offset().y();
    if(!direction) return;

    /* Move towards/backwards the rotation point in cam coords */
    _cameraObject->translateLocal(_rotationPoint*(direction < 0 ? -1.0f : 1.0f)*0.1f);

    redraw();
}

void MouseInteractionExample::drawEvent() {
    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth);

    _camera->draw(_drawables);

    swapBuffers();
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::MouseInteractionExample)
<|endoftext|>


<commit_before>// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef VK_OBJECT_HPP_
#define VK_OBJECT_HPP_

#include "VkConfig.h"
#include "VkDebug.hpp"
#include "VkMemory.h"

#include <vulkan/vulkan_core.h>
#include <vulkan/vk_icd.h>

namespace vk
{
// For use in the placement new to make it verbose that we're allocating an object using device memory
static constexpr VkAllocationCallbacks* DEVICE_MEMORY = nullptr;

template<typename T, typename VkT, typename CreateInfo>
static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
{
	*outObject = VK_NULL_HANDLE;

	size_t size = T::ComputeRequiredAllocationSize(pCreateInfo);
	void* memory = nullptr;
	if(size)
	{
		memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope());
		if(!memory)
		{
			return VK_ERROR_OUT_OF_HOST_MEMORY;
		}
	}

	auto object = new (pAllocator) T(pCreateInfo, memory);

	if(!object)
	{
		vk::deallocate(memory, pAllocator);
		return VK_ERROR_OUT_OF_HOST_MEMORY;
	}

	*outObject = *object;

	return VK_SUCCESS;
}

template<typename T, typename VkT>
class ObjectBase
{
public:
	using VkType = VkT;

	void destroy(const VkAllocationCallbacks* pAllocator) {} // Method defined by objects to delete their content, if necessary

	void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
	{
		return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
	}

	void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
	{
		// Should never happen
		ASSERT(false);
	}

	template<typename CreateInfo>
	static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
	{
		return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
	}

	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }

protected:
	// All derived classes should have deleted destructors
	~ObjectBase() {}
};

template<typename T, typename VkT>
class Object : public ObjectBase<T, VkT>
{
public:
	operator VkT()
	{
		return reinterpret_cast<VkT>(this);
	}
};

template<typename T, typename VkT>
class DispatchableObject
{
	VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };

	T object;
public:
	static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); }

	template<typename ...Args>
	DispatchableObject(Args... args) : object(args...)
	{
	}

	~DispatchableObject() = delete;

	void destroy(const VkAllocationCallbacks* pAllocator)
	{
		object.destroy(pAllocator);
	}

	void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
	{
		return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
	}

	void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
	{
		// Should never happen
		ASSERT(false);
	}

	template<typename CreateInfo>
	static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
	{
		return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
	}

	template<typename CreateInfo>
	static size_t ComputeRequiredAllocationSize(const CreateInfo* pCreateInfo)
	{
		return T::ComputeRequiredAllocationSize(pCreateInfo);
	}

	static inline T* Cast(VkT vkObject)
	{
		return &(reinterpret_cast<DispatchableObject<T, VkT>*>(vkObject)->object);
	}

	operator VkT()
	{
		return reinterpret_cast<VkT>(this);
	}
};

} // namespace vk

#endif // VK_OBJECT_HPP_
<commit_msg>Allow null dispatchable objects<commit_after>// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef VK_OBJECT_HPP_
#define VK_OBJECT_HPP_

#include "VkConfig.h"
#include "VkDebug.hpp"
#include "VkMemory.h"

#include <vulkan/vulkan_core.h>
#include <vulkan/vk_icd.h>

namespace vk
{
// For use in the placement new to make it verbose that we're allocating an object using device memory
static constexpr VkAllocationCallbacks* DEVICE_MEMORY = nullptr;

template<typename T, typename VkT, typename CreateInfo>
static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
{
	*outObject = VK_NULL_HANDLE;

	size_t size = T::ComputeRequiredAllocationSize(pCreateInfo);
	void* memory = nullptr;
	if(size)
	{
		memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope());
		if(!memory)
		{
			return VK_ERROR_OUT_OF_HOST_MEMORY;
		}
	}

	auto object = new (pAllocator) T(pCreateInfo, memory);

	if(!object)
	{
		vk::deallocate(memory, pAllocator);
		return VK_ERROR_OUT_OF_HOST_MEMORY;
	}

	*outObject = *object;

	return VK_SUCCESS;
}

template<typename T, typename VkT>
class ObjectBase
{
public:
	using VkType = VkT;

	void destroy(const VkAllocationCallbacks* pAllocator) {} // Method defined by objects to delete their content, if necessary

	void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
	{
		return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
	}

	void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
	{
		// Should never happen
		ASSERT(false);
	}

	template<typename CreateInfo>
	static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
	{
		return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
	}

	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }

protected:
	// All derived classes should have deleted destructors
	~ObjectBase() {}
};

template<typename T, typename VkT>
class Object : public ObjectBase<T, VkT>
{
public:
	operator VkT()
	{
		return reinterpret_cast<VkT>(this);
	}
};

template<typename T, typename VkT>
class DispatchableObject
{
	VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };

	T object;
public:
	static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); }

	template<typename ...Args>
	DispatchableObject(Args... args) : object(args...)
	{
	}

	~DispatchableObject() = delete;

	void destroy(const VkAllocationCallbacks* pAllocator)
	{
		object.destroy(pAllocator);
	}

	void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
	{
		return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
	}

	void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
	{
		// Should never happen
		ASSERT(false);
	}

	template<typename CreateInfo>
	static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
	{
		return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
	}

	template<typename CreateInfo>
	static size_t ComputeRequiredAllocationSize(const CreateInfo* pCreateInfo)
	{
		return T::ComputeRequiredAllocationSize(pCreateInfo);
	}

	static inline T* Cast(VkT vkObject)
	{
		return (vkObject == VK_NULL_HANDLE) ? nullptr :
		       &(reinterpret_cast<DispatchableObject<T, VkT>*>(vkObject)->object);
	}

	operator VkT()
	{
		return reinterpret_cast<VkT>(this);
	}
};

} // namespace vk

#endif // VK_OBJECT_HPP_
<|endoftext|>


<commit_before>#include "oop.hpp"
#include "vm.hpp"
#include "objectmemory.hpp"
#include "gc/inflated_headers.hpp"

#include <iostream>

namespace rubinius {
  /**
   * Allocates a new InflatedHeader object for the specified obj ObjectHeader.
   *
   * /param obj The ObjectHeader that is to be inflated.
   * /returns the InflatedHeader representing the new inflated object header.
   */
  InflatedHeader* InflatedHeaders::allocate(ObjectHeader* obj) {
    bool needs_gc = false;
    InflatedHeader* header = allocator_->allocate(&needs_gc);
    header->set_object(obj);
    if(needs_gc) {
      state_->om->collect_mature_now = true;
    }
    return header;
  }

  /**
   * Scans the list of InflatedHeader objects checking to see which are in use.
   * Those that do not have the appropriate mark value set are cleared and
   * added back to the free list. Chunks that are completely unused are removed
   * from the linked list.
   *
   * /param mark The current value of the mark; only InflatedHeaders that bear
   *             this mark will be retained.
   */
  void InflatedHeaders::deallocate_headers(int mark) {
    std::vector<bool> chunk_marks(allocator_->chunks_.size(), false);
    for(std::vector<int>::size_type i = 0; i < allocator_->chunks_.size(); ++i) {
      InflatedHeader* chunk = allocator_->chunks_[i];

      for(size_t j = 0; j < allocator_->cChunkSize; j++) {
        InflatedHeader* header = &chunk[j];

        if(header->in_use_p()) {
          if(header->marked_p(mark)) {
            chunk_marks[i] = true;
            break;
          } else {
            header->clear();
          }
        }
      }
    }

    allocator_->rebuild_freelist(&chunk_marks);
  }
}
<commit_msg>Don't break the loop when cleaning up handles<commit_after>#include "oop.hpp"
#include "vm.hpp"
#include "objectmemory.hpp"
#include "gc/inflated_headers.hpp"

#include <iostream>

namespace rubinius {
  /**
   * Allocates a new InflatedHeader object for the specified obj ObjectHeader.
   *
   * /param obj The ObjectHeader that is to be inflated.
   * /returns the InflatedHeader representing the new inflated object header.
   */
  InflatedHeader* InflatedHeaders::allocate(ObjectHeader* obj) {
    bool needs_gc = false;
    InflatedHeader* header = allocator_->allocate(&needs_gc);
    header->set_object(obj);
    if(needs_gc) {
      state_->om->collect_mature_now = true;
    }
    return header;
  }

  /**
   * Scans the list of InflatedHeader objects checking to see which are in use.
   * Those that do not have the appropriate mark value set are cleared and
   * added back to the free list. Chunks that are completely unused are removed
   * from the linked list.
   *
   * /param mark The current value of the mark; only InflatedHeaders that bear
   *             this mark will be retained.
   */
  void InflatedHeaders::deallocate_headers(int mark) {
    std::vector<bool> chunk_marks(allocator_->chunks_.size(), false);
    for(std::vector<int>::size_type i = 0; i < allocator_->chunks_.size(); ++i) {
      InflatedHeader* chunk = allocator_->chunks_[i];

      for(size_t j = 0; j < allocator_->cChunkSize; j++) {
        InflatedHeader* header = &chunk[j];

        if(header->in_use_p()) {
          if(header->marked_p(mark)) {
            chunk_marks[i] = true;
          } else {
            header->clear();
          }
        }
      }
    }

    allocator_->rebuild_freelist(&chunk_marks);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Mirants Lu. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "voyager/rpc/rpc_channel.h"

#include <string>

namespace voyager {

RpcChannel::RpcChannel(EventLoop* loop)
    : loop_(loop),
      micros_(5 * 1000 * 1000) {
}

RpcChannel::~RpcChannel() {
  for (auto it : call_map_) {
    delete it.second.response;
    delete it.second.done;
    loop_->RemoveTimer(it.second.timer);
  }
}

void RpcChannel::CallMethod(const google::protobuf::MethodDescriptor* method,
                            google::protobuf::RpcController* controller,
                            const google::protobuf::Message* request,
                            google::protobuf::Message* response,
                            google::protobuf::Closure* done) {
  int id = num_.GetNext();
  RpcMessage msg;
  msg.set_id(id);
  msg.set_service_name(method->service()->full_name());
  msg.set_method_name(method->name());
  msg.set_data(request->SerializeAsString());

  std::string s;
  if (codec_.SerializeToString(msg, &s)) {
    conn_->SendMessage(s);
    Timer* t = loop_->RunAfter(
        micros_, std::bind(&RpcChannel::TimeoutHandler, this, id));
    port::MutexLock lock(&mutex_);
    call_map_[id] = CallData(response, done, t);
  } else {
    if (error_cb_) {
      error_cb_(ERROR_CODE_UNKNOWN);
    }
    delete response;
    delete done;
  }
}

void RpcChannel::OnMessage(const TcpConnectionPtr& p, Buffer* buf) {
  RpcMessage msg;
  bool res = codec_.ParseFromBuffer(buf, &msg);
  while (res) {
    OnResponse(msg);
    res = codec_.ParseFromBuffer(buf, &msg);
  }
}

void RpcChannel::TimeoutHandler(int id) {
  {
    port::MutexLock lock(&mutex_);
    auto it = call_map_.find(id);
    if (it != call_map_.end()) {
      delete it->second.response;
      delete it->second.done;
      call_map_.erase(it);
    }
  }
  if (error_cb_) {
    error_cb_(ERROR_CODE_TIMEOUT);
  }
}

void RpcChannel::OnResponse(const RpcMessage& msg) {
  int id = msg.id();
  CallData data;
  {
    port::MutexLock lock(&mutex_);
    auto it = call_map_.find(id);
    if (it != call_map_.end()) {
      data = it->second;
      call_map_.erase(it);
    }
  }
  loop_->RemoveTimer(data.timer);

  if (msg.error() == ERROR_CODE_OK) {
    if (data.response) {
      data.response->ParseFromString(msg.data());
    }
    if (data.done) {
      data.done->Run();
    }
  } else {
    if (error_cb_) {
      error_cb_(msg.error());
    }
    delete data.done;
  }
  delete data.response;
}

}  // namespace voyager
<commit_msg>fix rpc timer<commit_after>// Copyright (c) 2016 Mirants Lu. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "voyager/rpc/rpc_channel.h"

#include <string>

namespace voyager {

RpcChannel::RpcChannel(EventLoop* loop)
    : loop_(loop),
      micros_(0) {
}

RpcChannel::~RpcChannel() {
  for (auto it : call_map_) {
    delete it.second.response;
    delete it.second.done;
    if (it.second.timer) {
      loop_->RemoveTimer(it.second.timer);
    }
  }
}

void RpcChannel::CallMethod(const google::protobuf::MethodDescriptor* method,
                            google::protobuf::RpcController* controller,
                            const google::protobuf::Message* request,
                            google::protobuf::Message* response,
                            google::protobuf::Closure* done) {
  int id = num_.GetNext();
  RpcMessage msg;
  msg.set_id(id);
  msg.set_service_name(method->service()->full_name());
  msg.set_method_name(method->name());
  msg.set_data(request->SerializeAsString());

  std::string s;
  if (codec_.SerializeToString(msg, &s)) {
    conn_->SendMessage(s);
    Timer* t = nullptr;
    if (micros_ > 0) {
      loop_->RunAfter(
          micros_, std::bind(&RpcChannel::TimeoutHandler, this, id));
    }
    port::MutexLock lock(&mutex_);
    call_map_[id] = CallData(response, done, t);
  } else {
    if (error_cb_) {
      error_cb_(ERROR_CODE_UNKNOWN);
    }
    delete response;
    delete done;
  }
}

void RpcChannel::OnMessage(const TcpConnectionPtr& p, Buffer* buf) {
  RpcMessage msg;
  bool res = codec_.ParseFromBuffer(buf, &msg);
  while (res) {
    OnResponse(msg);
    res = codec_.ParseFromBuffer(buf, &msg);
  }
}

void RpcChannel::TimeoutHandler(int id) {
  {
    port::MutexLock lock(&mutex_);
    auto it = call_map_.find(id);
    if (it != call_map_.end()) {
      delete it->second.response;
      delete it->second.done;
      call_map_.erase(it);
    }
  }
  if (error_cb_) {
    error_cb_(ERROR_CODE_TIMEOUT);
  }
}

void RpcChannel::OnResponse(const RpcMessage& msg) {
  int id = msg.id();
  CallData data;
  {
    port::MutexLock lock(&mutex_);
    auto it = call_map_.find(id);
    if (it != call_map_.end()) {
      data = it->second;
      call_map_.erase(it);
    }
  }
  if (data.timer) {
    loop_->RemoveTimer(data.timer);
  }
  if (msg.error() == ERROR_CODE_OK) {
    if (data.response) {
      data.response->ParseFromString(msg.data());
    }
    if (data.done) {
      data.done->Run();
    }
  } else {
    if (error_cb_) {
      error_cb_(msg.error());
    }
    delete data.done;
  }
  delete data.response;
}

}  // namespace voyager
<|endoftext|>