<commit_before>#include <common/log.h>
#include <common/pty.h>
#include <common/string.h>
#include <common/file.h>
#include <common/list.h>
#include <gui/gui.h>
#include <gdb/gdb.h>
#include <gdb/frame.h>
#include <gdb/parser.tab.h>
#include <user_cmd/cmd.hash.h>
#include <user_cmd/subcmd.hash.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <math.h>
#include <unistd.h>

/* global variables */
gdbif* gdb = 0;

/* class definition */
/**
 * \brief	standard constructor
 */
gdbif::gdbif(){
	main_tid = 0;
	read_tid = 0;
	gdb = 0;
	token = 1;
	is_running = false;
	event_lst = 0;
	stop_hdlr = 0;
	cur_thread = -1;

	pthread_mutex_init(&resp_mtx, 0);
	pthread_mutex_init(&event_mtx, 0);
	pthread_cond_init(&resp_avail, 0);
	pthread_cond_init(&event_avail, 0);
}

/**
 * \brief	standard desctructor
 */
gdbif::~gdbif(){
	// close gdb terminal
	delete this->gdb;

	if(read_tid != 0)
		pthread_join(read_tid, 0);

	if(event_tid != 0){
		pthread_cancel(event_tid);
		pthread_join(event_tid, 0);
	}

	pthread_cond_destroy(&resp_avail);
	pthread_cond_destroy(&event_avail);
	pthread_mutex_destroy(&resp_mtx);
	pthread_mutex_destroy(&event_mtx);
}

/**
 * \brief	exec gdb and initialise its controlling terminal
 *
 * \return	0	on success
 * 			-1	on error (check errno)
 */
int gdbif::init(pthread_t main_tid){
	this->main_tid = main_tid;

	// initialise pseudo terminal
	this->gdb = new pty();

	// fork child process
	gdb_pid = gdb->fork();

	if(gdb_pid == 0){
		/* child */
		log::cleanup();

		return execl(GDB_CMD, GDB_CMD, GDB_ARGS, (char*)0);
	}
	else if(gdb_pid > 0){
		/* parent */
		if(pthread_create(&read_tid, 0, readline_thread, this) != 0)
			return -1;

		thread_name[read_tid] = "gdb-readline";

		if(pthread_create(&event_tid, 0, event_thread, this) != 0)
			return -1;

		thread_name[event_tid] = "gdb-event";
		return 0;
	}
	else{
		/* error */
		return -1;
	}
}

void gdbif::on_stop(int (*hdlr)(void)){
	stop_hdlr_t* e;

	e = new stop_hdlr_t;
	e->hdlr = hdlr;

	list_add_tail(&stop_hdlr, e);
}

/**
 * \brief	create gdb machine interface (MI) command
 *
 * \param	cmd		target command
 * \param	fmt		printf-like format string, describing the following parameters
 * 					supported identifiers:
 * 						'%d'		integer
 * 						'%s'		string
 * 						'%ss %d'	array of strings, length is defined by the
 * 									following integer
 * 						'--'		separator between options and parameters
 * 						.			everything else except blanks is printed literaly
 *
 * \param	...		parameters according to param_fmt
 *
 * \return	>0		token used for the command
 * 			-1		error
 */
int gdbif::mi_issue_cmd(char* cmd, gdb_result_class_t ok_mask, int(*process)(gdb_result_t*, void**), void** r, const char* fmt, ...){
	static char* volatile s = 0;
	static unsigned int volatile s_len = 0;
	static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
	unsigned int i, j, argc;
	char** argv;
	va_list lst;

	pthread_mutex_lock(&m);

	va_start(lst, fmt);

	gdb->write(itoa(token, (char**)&s, (unsigned int*)&s_len));
	gdb->write((char*)"-");
	gdb->write(cmd);

	if(*fmt != 0)
		gdb->write((char*)" ");

	for(i=0; i<strlen(fmt); i++){
		switch(fmt[i]){
		case '%':
			switch(fmt[i + 1]){
			case 'd':
				gdb->write(itoa((int)va_arg(lst, int), (char**)&s, (unsigned int*)&s_len));
				i++;
				break;

			case 'u':
				gdb->write(itoa((unsigned int)va_arg(lst, unsigned int), (char**)&s, (unsigned int*)&s_len));
				i++;
				break;

			case 's':
				if(strncmp(fmt + i + 2, "s %d", 4) == 0){
					argv = va_arg(lst, char**);
					argc = va_arg(lst, int);

					for(j=0; j<argc; j++)
						gdb->write(argv[j]);

					i += 4;
				}
				else
					gdb->write(va_arg(lst, char*));

				i++;
				break;

			default:
				pthread_mutex_unlock(&m);
				va_end(lst);

				ERROR("invalid format sequence %%%c\n", fmt[i + 1]);
				return -1;
			};

			break;

		default:
			gdb->write((void*)(fmt + i), 1);
			break;
		};
	}

	/* wait for gdb response */
	pthread_mutex_lock(&resp_mtx);

	memset((void*)&resp, 0x0, sizeof(response_t));

	gdb->write((char*)"\n");	// ensure that response cannot arrive
								// before it is expected

	pthread_cond_wait(&resp_avail, &resp_mtx);

	token++;

	if((resp.rclass & ok_mask)){
		if(resp.result){
			if(process){
				if(process(resp.result, r) != 0){
					ERROR("unable to process result for \"%s\"\n", cmd);
					resp.rclass = RC_ERROR;
				}
			}
			else if(r){
				*r = (void**)resp.result;
				resp.result = 0;
			}
		}
	}
	else
		USER("gdb-error %s: \"%s\"\n", cmd, (resp.result ? resp.result->value->value : "gdb implementation error"));

	gdb_result_free(resp.result);

	pthread_mutex_unlock(&resp_mtx);
	pthread_mutex_unlock(&m);

	va_end(lst);

	if(resp.rclass & ok_mask)
		return 0;
	return -1;
}

int gdbif::mi_proc_result(gdb_result_class_t rclass, unsigned int token, gdb_result_t* result){
	pthread_mutex_lock(&resp_mtx);

	if(this->token != token)
		ERROR("result token (%d) doesn't match issued token (%d)\n", token, this->token);

	resp.result = result;
	resp.rclass = rclass;

	pthread_cond_signal(&resp_avail);
	pthread_mutex_unlock(&resp_mtx);

	return 0;
}

int gdbif::mi_proc_async(gdb_result_class_t rclass, unsigned int token, gdb_result_t* result){
	int r;
	response_t* e;

	pthread_mutex_lock(&event_mtx);

	switch(rclass){
	case RC_STOPPED:
	case RC_RUNNING:
		e = new response_t;

		e->rclass = rclass;
		e->result = result;
		list_add_tail(&event_lst, e);

		pthread_cond_signal(&event_avail);
		break;

	default:
		GDB("unhandled gdb-event %d\n", rclass);
		gdb_result_free(result);
	};

	pthread_mutex_unlock(&event_mtx);

	return 0;
}

int gdbif::mi_proc_stream(gdb_stream_class_t sclass, char* stream){
	USER("%s", strdeescape(stream));	// use "%s" to avoid issues with '%' within stream
	return 0;
}

/**
 * \brief	read from gdb terminal
 *
 * \param	buf		target buffer
 * \param	nbytes	max bytes to read
 *
 * \return	number of read bytes on success
 * 			-1 on error
 */
int gdbif::read(void* buf, unsigned int nbytes){
	return gdb->read(buf, nbytes);
}

/**
 * \brief	write to gdb terminal
 *
 * \param	buf		source buffer
 * \param	nbytes	number of bytes to write
 *
 * \return	number of written bytes on success
 * 			-1 on error
 */
int gdbif::write(void* buf, unsigned int nbytes){
	return gdb->write(buf, nbytes);
}

int gdbif::sigsend(int sig){
	sigval v;

	return sigqueue(gdb_pid, sig, v);
}

bool gdbif::running(){
	return is_running;
}

bool gdbif::running(bool state){
	return (is_running = state);
}

unsigned int gdbif::threadid(){
	return cur_thread;
}

void* gdbif::readline_thread(void* arg){
	char c, *line;
	unsigned int i, len;
	gdbif* gdb;
	sigval v;

	i = 0;
	gdb = (gdbif*)arg;

	len = 255;
	line = (char*)malloc(len * sizeof(char));

	if(line == 0)
		goto err_0;

#ifdef GUI_CURSES
	if(ui->win_create("gdb-log", true, 0) < 0)
		goto err_1;
#endif // GUI_CURSES

	while(1){
		if(gdb->read(&c, 1) == 1){
			// ignore CR to avoid issues when printing the string
			if(c == '\r')
				continue;

			line[i++] = c;

			if(i >= len){
				len *= 2;
				line = (char*)realloc(line, len);

				if(line == 0)
					goto err_2;
			}

			// check for end of gdb line, a simple newline as separator
			// doesn't work, since the parse would try to parse the line,
			// detecting a syntax error
			if(strncmp(line + i - 6, "(gdb)\n", 6) == 0 ||
			   strncmp(line + i - 7, "(gdb) \n", 7) == 0
			  ){
				line[i] = 0;

				GDB("parse gdb string \"%.10s\"\n", line);
				ui->win_print(ui->win_getid("gdb-log"), "%s", line);		// use "%s" to avoid issues with '%' within line

				i = gdbparse(line, gdb);

				GDB("parser return value: %d\n", i);
				ui->win_print(ui->win_getid("gdb-log"), "parser return value: %d\n", i);

				i = 0;
			}
		}
		else{
			DEBUG("gdb read shutdown\n");
			break;
		}
	}

err_2:
	ui->win_destroy(ui->win_getid("gdb-log"));

err_1:
	free(line);

err_0:
	pthread_sigqueue(gdb->main_tid, SIGTERM, v);
	pthread_exit(0);
}

void* gdbif::event_thread(void* arg){
	int r;
	gdbif* gdb;
	response_t* e;

	gdb = (gdbif*)arg;

	while(1){
		pthread_mutex_lock(&gdb->event_mtx);

		if(list_empty(gdb->event_lst))
			pthread_cond_wait(&gdb->event_avail, &gdb->event_mtx);

		e = list_first(gdb->event_lst);
		list_rm(&gdb->event_lst, e);

		pthread_mutex_unlock(&gdb->event_mtx);

		switch(e->rclass){
		case RC_STOPPED:
			GDB("handle event STOPPED\n");
			r = gdb->evt_stopped(e->result);
			break;

		case RC_RUNNING:
			GDB("handle event RUNNING\n");
			r = gdb->evt_running(e->result);
			break;

		default:
			r = -1;
		};

		if(r != 0)
			ERROR("error handling gdb-event %d\n", e->rclass);

		gdb_result_free(e->result);
		delete e;
	}
}

int gdbif::evt_running(gdb_result_t* result){
	running(true);
	return 0;
}

int gdbif::evt_stopped(gdb_result_t* result){
	char* reason;
	gdb_result_t* r;
	gdb_frame_t* frame;
	stop_hdlr_t* e;

	reason = 0;
	frame = 0;

	running(false);

	/* parse result */
	list_for_each(result, r){
		switch(r->var_id){
		case IDV_REASON:
			reason = (char*)r->value->value;
			break;

		case IDV_FRAME:
			gdb_frame_t::result_to_frame((gdb_result_t*)r->value->value, &frame);
			break;

		case IDV_THREAD_ID:
			cur_thread = atoi((char*)r->value->value);
			break;

		default:
			break;
		};
	}

	if(reason == 0)
		goto err;

	/* check reason */
	if(reason != 0 && frame != 0){
		if(FILE_EXISTS(frame->fullname)){
			ui->win_anno_add(ui->win_create(frame->fullname), frame->line, "ip", "White", "Black");
			ui->win_cursor_set(ui->win_create(frame->fullname), frame->line);
		}
		else
			USER("file \"%s\" does not exist\n", frame->fullname);
	}
	else if(strcmp(reason, "exited-normally") == 0){
		USER("program exited\n");
		goto end;
	}

	/* update variables */
	gdb_variable_t::get_changed();

	/* execute callbacks */
	list_for_each(stop_hdlr, e){
		if(e->hdlr() != 0)
			USER("error executing on-stop handler\n");
	}

end:
	delete frame;
	return 0;

err:
	delete frame;
	return -1;
}
<commit_msg>[fix: gdbif default threadid]<commit_after>#include <common/log.h>
#include <common/pty.h>
#include <common/string.h>
#include <common/file.h>
#include <common/list.h>
#include <gui/gui.h>
#include <gdb/gdb.h>
#include <gdb/frame.h>
#include <gdb/parser.tab.h>
#include <user_cmd/cmd.hash.h>
#include <user_cmd/subcmd.hash.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <math.h>
#include <unistd.h>

/* global variables */
gdbif* gdb = 0;

/* class definition */
/**
 * \brief	standard constructor
 */
gdbif::gdbif(){
	main_tid = 0;
	read_tid = 0;
	gdb = 0;
	token = 1;
	is_running = false;
	event_lst = 0;
	stop_hdlr = 0;
	cur_thread = 0;

	pthread_mutex_init(&resp_mtx, 0);
	pthread_mutex_init(&event_mtx, 0);
	pthread_cond_init(&resp_avail, 0);
	pthread_cond_init(&event_avail, 0);
}

/**
 * \brief	standard desctructor
 */
gdbif::~gdbif(){
	// close gdb terminal
	delete this->gdb;

	if(read_tid != 0)
		pthread_join(read_tid, 0);

	if(event_tid != 0){
		pthread_cancel(event_tid);
		pthread_join(event_tid, 0);
	}

	pthread_cond_destroy(&resp_avail);
	pthread_cond_destroy(&event_avail);
	pthread_mutex_destroy(&resp_mtx);
	pthread_mutex_destroy(&event_mtx);
}

/**
 * \brief	exec gdb and initialise its controlling terminal
 *
 * \return	0	on success
 * 			-1	on error (check errno)
 */
int gdbif::init(pthread_t main_tid){
	this->main_tid = main_tid;

	// initialise pseudo terminal
	this->gdb = new pty();

	// fork child process
	gdb_pid = gdb->fork();

	if(gdb_pid == 0){
		/* child */
		log::cleanup();

		return execl(GDB_CMD, GDB_CMD, GDB_ARGS, (char*)0);
	}
	else if(gdb_pid > 0){
		/* parent */
		if(pthread_create(&read_tid, 0, readline_thread, this) != 0)
			return -1;

		thread_name[read_tid] = "gdb-readline";

		if(pthread_create(&event_tid, 0, event_thread, this) != 0)
			return -1;

		thread_name[event_tid] = "gdb-event";
		return 0;
	}
	else{
		/* error */
		return -1;
	}
}

void gdbif::on_stop(int (*hdlr)(void)){
	stop_hdlr_t* e;

	e = new stop_hdlr_t;
	e->hdlr = hdlr;

	list_add_tail(&stop_hdlr, e);
}

/**
 * \brief	create gdb machine interface (MI) command
 *
 * \param	cmd		target command
 * \param	fmt		printf-like format string, describing the following parameters
 * 					supported identifiers:
 * 						'%d'		integer
 * 						'%s'		string
 * 						'%ss %d'	array of strings, length is defined by the
 * 									following integer
 * 						'--'		separator between options and parameters
 * 						.			everything else except blanks is printed literaly
 *
 * \param	...		parameters according to param_fmt
 *
 * \return	>0		token used for the command
 * 			-1		error
 */
int gdbif::mi_issue_cmd(char* cmd, gdb_result_class_t ok_mask, int(*process)(gdb_result_t*, void**), void** r, const char* fmt, ...){
	static char* volatile s = 0;
	static unsigned int volatile s_len = 0;
	static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
	unsigned int i, j, argc;
	char** argv;
	va_list lst;

	pthread_mutex_lock(&m);

	va_start(lst, fmt);

	gdb->write(itoa(token, (char**)&s, (unsigned int*)&s_len));
	gdb->write((char*)"-");
	gdb->write(cmd);

	if(*fmt != 0)
		gdb->write((char*)" ");

	for(i=0; i<strlen(fmt); i++){
		switch(fmt[i]){
		case '%':
			switch(fmt[i + 1]){
			case 'd':
				gdb->write(itoa((int)va_arg(lst, int), (char**)&s, (unsigned int*)&s_len));
				i++;
				break;

			case 'u':
				gdb->write(itoa((unsigned int)va_arg(lst, unsigned int), (char**)&s, (unsigned int*)&s_len));
				i++;
				break;

			case 's':
				if(strncmp(fmt + i + 2, "s %d", 4) == 0){
					argv = va_arg(lst, char**);
					argc = va_arg(lst, int);

					for(j=0; j<argc; j++)
						gdb->write(argv[j]);

					i += 4;
				}
				else
					gdb->write(va_arg(lst, char*));

				i++;
				break;

			default:
				pthread_mutex_unlock(&m);
				va_end(lst);

				ERROR("invalid format sequence %%%c\n", fmt[i + 1]);
				return -1;
			};

			break;

		default:
			gdb->write((void*)(fmt + i), 1);
			break;
		};
	}

	/* wait for gdb response */
	pthread_mutex_lock(&resp_mtx);

	memset((void*)&resp, 0x0, sizeof(response_t));

	gdb->write((char*)"\n");	// ensure that response cannot arrive
								// before it is expected

	pthread_cond_wait(&resp_avail, &resp_mtx);

	token++;

	if((resp.rclass & ok_mask)){
		if(resp.result){
			if(process){
				if(process(resp.result, r) != 0){
					ERROR("unable to process result for \"%s\"\n", cmd);
					resp.rclass = RC_ERROR;
				}
			}
			else if(r){
				*r = (void**)resp.result;
				resp.result = 0;
			}
		}
	}
	else
		USER("gdb-error %s: \"%s\"\n", cmd, (resp.result ? resp.result->value->value : "gdb implementation error"));

	gdb_result_free(resp.result);

	pthread_mutex_unlock(&resp_mtx);
	pthread_mutex_unlock(&m);

	va_end(lst);

	if(resp.rclass & ok_mask)
		return 0;
	return -1;
}

int gdbif::mi_proc_result(gdb_result_class_t rclass, unsigned int token, gdb_result_t* result){
	pthread_mutex_lock(&resp_mtx);

	if(this->token != token)
		ERROR("result token (%d) doesn't match issued token (%d)\n", token, this->token);

	resp.result = result;
	resp.rclass = rclass;

	pthread_cond_signal(&resp_avail);
	pthread_mutex_unlock(&resp_mtx);

	return 0;
}

int gdbif::mi_proc_async(gdb_result_class_t rclass, unsigned int token, gdb_result_t* result){
	int r;
	response_t* e;

	pthread_mutex_lock(&event_mtx);

	switch(rclass){
	case RC_STOPPED:
	case RC_RUNNING:
		e = new response_t;

		e->rclass = rclass;
		e->result = result;
		list_add_tail(&event_lst, e);

		pthread_cond_signal(&event_avail);
		break;

	default:
		GDB("unhandled gdb-event %d\n", rclass);
		gdb_result_free(result);
	};

	pthread_mutex_unlock(&event_mtx);

	return 0;
}

int gdbif::mi_proc_stream(gdb_stream_class_t sclass, char* stream){
	USER("%s", strdeescape(stream));	// use "%s" to avoid issues with '%' within stream
	return 0;
}

/**
 * \brief	read from gdb terminal
 *
 * \param	buf		target buffer
 * \param	nbytes	max bytes to read
 *
 * \return	number of read bytes on success
 * 			-1 on error
 */
int gdbif::read(void* buf, unsigned int nbytes){
	return gdb->read(buf, nbytes);
}

/**
 * \brief	write to gdb terminal
 *
 * \param	buf		source buffer
 * \param	nbytes	number of bytes to write
 *
 * \return	number of written bytes on success
 * 			-1 on error
 */
int gdbif::write(void* buf, unsigned int nbytes){
	return gdb->write(buf, nbytes);
}

int gdbif::sigsend(int sig){
	sigval v;

	return sigqueue(gdb_pid, sig, v);
}

bool gdbif::running(){
	return is_running;
}

bool gdbif::running(bool state){
	return (is_running = state);
}

unsigned int gdbif::threadid(){
	return cur_thread;
}

void* gdbif::readline_thread(void* arg){
	char c, *line;
	unsigned int i, len;
	gdbif* gdb;
	sigval v;

	i = 0;
	gdb = (gdbif*)arg;

	len = 255;
	line = (char*)malloc(len * sizeof(char));

	if(line == 0)
		goto err_0;

#ifdef GUI_CURSES
	if(ui->win_create("gdb-log", true, 0) < 0)
		goto err_1;
#endif // GUI_CURSES

	while(1){
		if(gdb->read(&c, 1) == 1){
			// ignore CR to avoid issues when printing the string
			if(c == '\r')
				continue;

			line[i++] = c;

			if(i >= len){
				len *= 2;
				line = (char*)realloc(line, len);

				if(line == 0)
					goto err_2;
			}

			// check for end of gdb line, a simple newline as separator
			// doesn't work, since the parse would try to parse the line,
			// detecting a syntax error
			if(strncmp(line + i - 6, "(gdb)\n", 6) == 0 ||
			   strncmp(line + i - 7, "(gdb) \n", 7) == 0
			  ){
				line[i] = 0;

				GDB("parse gdb string \"%.10s\"\n", line);
				ui->win_print(ui->win_getid("gdb-log"), "%s", line);		// use "%s" to avoid issues with '%' within line

				i = gdbparse(line, gdb);

				GDB("parser return value: %d\n", i);
				ui->win_print(ui->win_getid("gdb-log"), "parser return value: %d\n", i);

				i = 0;
			}
		}
		else{
			DEBUG("gdb read shutdown\n");
			break;
		}
	}

err_2:
	ui->win_destroy(ui->win_getid("gdb-log"));

err_1:
	free(line);

err_0:
	pthread_sigqueue(gdb->main_tid, SIGTERM, v);
	pthread_exit(0);
}

void* gdbif::event_thread(void* arg){
	int r;
	gdbif* gdb;
	response_t* e;

	gdb = (gdbif*)arg;

	while(1){
		pthread_mutex_lock(&gdb->event_mtx);

		if(list_empty(gdb->event_lst))
			pthread_cond_wait(&gdb->event_avail, &gdb->event_mtx);

		e = list_first(gdb->event_lst);
		list_rm(&gdb->event_lst, e);

		pthread_mutex_unlock(&gdb->event_mtx);

		switch(e->rclass){
		case RC_STOPPED:
			GDB("handle event STOPPED\n");
			r = gdb->evt_stopped(e->result);
			break;

		case RC_RUNNING:
			GDB("handle event RUNNING\n");
			r = gdb->evt_running(e->result);
			break;

		default:
			r = -1;
		};

		if(r != 0)
			ERROR("error handling gdb-event %d\n", e->rclass);

		gdb_result_free(e->result);
		delete e;
	}
}

int gdbif::evt_running(gdb_result_t* result){
	running(true);
	return 0;
}

int gdbif::evt_stopped(gdb_result_t* result){
	char* reason;
	gdb_result_t* r;
	gdb_frame_t* frame;
	stop_hdlr_t* e;

	reason = 0;
	frame = 0;

	running(false);

	/* parse result */
	list_for_each(result, r){
		switch(r->var_id){
		case IDV_REASON:
			reason = (char*)r->value->value;
			break;

		case IDV_FRAME:
			gdb_frame_t::result_to_frame((gdb_result_t*)r->value->value, &frame);
			break;

		case IDV_THREAD_ID:
			cur_thread = atoi((char*)r->value->value);
			break;

		default:
			break;
		};
	}

	if(reason == 0)
		goto err;

	/* check reason */
	if(reason != 0 && frame != 0){
		if(FILE_EXISTS(frame->fullname)){
			ui->win_anno_add(ui->win_create(frame->fullname), frame->line, "ip", "White", "Black");
			ui->win_cursor_set(ui->win_create(frame->fullname), frame->line);
		}
		else
			USER("file \"%s\" does not exist\n", frame->fullname);
	}
	else if(strcmp(reason, "exited-normally") == 0){
		USER("program exited\n");
		goto end;
	}

	/* update variables */
	gdb_variable_t::get_changed();

	/* execute callbacks */
	list_for_each(stop_hdlr, e){
		if(e->hdlr() != 0)
			USER("error executing on-stop handler\n");
	}

end:
	delete frame;
	return 0;

err:
	delete frame;
	return -1;
}
<|endoftext|>


<commit_before>#ifndef MESCALINE_MEMORY_MANAGER_HPP_INCLUDED
#define MESCALINE_MEMORY_MANAGER_HPP_INCLUDED

#include <Mescaline/Exception.hpp>
#include <Mescaline/Memory.hpp>

#include <boost/cstdint.hpp>
#include <boost/lockfree/fifo.hpp>

namespace Mescaline { namespace Memory {

using namespace std;

class RTMemoryManager
{
public:
    // Primitives
    void* alloc(size_t numBytes)
        throw(MemoryAllocationFailure)
        { return Memory::alloc(numBytes); }
    template <size_t align> void* allocAligned(size_t numBytes)
        throw(MemoryAllocationFailure)
        { return Memory::allocAligned<align>(numBytes); }
    void free(void* ptr)
        throw(MemoryAllocationFailure)
        { Memory::free(ptr); }

    // Wrappers
    template <typename T> T* allocOf(size_t numElems=1)
        throw(MemoryAllocationFailure)
        { return Memory::allocOf<T>(numElems); }
    template <typename T, size_t align> T* allocAlignedOf(size_t numElems=1)
        throw(MemoryAllocationFailure)
        { return Memory::allocAligned<T,align>(numElems); }
};

template <class T, class Allocator, size_t align=kDefaultAlignment> class AllocatedBase
{
    struct Chunk
    {
        Allocator*  alloc;
        char        padding[MESCALINE_PADDING(align, sizeof(Allocator*))];
        char        data[];
    };

protected:
    static const size_t kAlignment = align;

    static void* alloc(Allocator& allocator, size_t size)
    {
        Chunk* chunk = static_cast<Chunk*>(allocator.allocAligned<align>(sizeof(Chunk) + size));
        chunk->alloc = &allocator;
        BOOST_ASSERT( MESCALINE_ISALIGNED(align, reinterpret_cast<size_t>(chunk->data)) );
        return chunk->data;
    }
    static void destroy(void* ptr)
    {
        cout << "AllocatedBase::free" << endl;
        Chunk* chunk = static_cast<Chunk*>(ptr) - 1;
        BOOST_ASSERT( chunk->data == ptr );
        static_cast<T*>(ptr)->~T();
        chunk->alloc->free(chunk);
    }

    void* operator new(size_t);
};

template <class T, class Allocator, size_t align=kDefaultAlignment> class Allocated
    : public AllocatedBase<T, Allocator, align>
{
    typedef AllocatedBase<T, Allocator, align> super;

public:
    void* operator new(size_t size, Allocator& alloc)
    {
        return super::alloc(alloc, size);
    }
    void operator delete(void* ptr, Allocator& alloc)
    {
        super::destroy(ptr);
    }
    void* operator new(size_t size, Allocator& alloc, size_t additional)
    {
        return super::alloc(alloc, size+additional);
    }
    void operator delete(void* ptr, Allocator& alloc, size_t realSize)
    {
        super::destroy(ptr);
    }
    void operator delete(void* ptr)
    {
        super::destroy(ptr);
    }
};

// template <class Manager> class DeferredMemoryManager
// {
// public:
//     typedef void (*Destructor)(void* ptr);
//
//     DeferredMemoryManager(Manager& mem)
//         : m_mem(mem)
//     { }
//
//     void* malloc(size_t size)
//     {
//         Chunk* chunk;
//         while (m_fifo.dequeue(chunk)) {
//             if (chunk->destroy != 0) {
//                 chunk->destroy(chunk->data);
//             }
//             m_mem.free(chunk);
//         }
//         cout << "DeferredMemoryManager::malloc" << endl;
//         chunk = static_cast<Chunk*>(m_mem.malloc(sizeof(Chunk) + size));
//         chunk->destroy = 0;
//         return chunk->data;
//     }
//     void free(Destructor destroy, void* ptr)
//     {
//         Chunk* chunk = static_cast<Chunk*>(ptr) - 1;
//         chunk->destroy = destroy;
//         do {
//             /* SPIN */
//         } while (!m_fifo.enqueue(chunk));
//     }
//
// private:
//     struct Chunk
//     {
//         Destructor  destroy;
//         char        data[];
//     };
//
//     Manager& m_mem;
//     boost::lockfree::fifo<Chunk*> m_fifo;
// };
//
// template <class T, class Manager> class AllocatedDeferredBase
// {
// public:
//     typedef DeferredMemoryManager<Manager> Allocator;
//
//     void* operator new(size_t size, Allocator& alloc)
//     {
//         Chunk* chunk = static_cast<Chunk*>(alloc.malloc(sizeof(Chunk) + size));
//         chunk->alloc = &alloc;
//         return chunk->data;
//     }
//     void operator delete(void* ptr, Allocator& alloc)
//     {
//         AllocatedDeferredBase<T, Manager>::free(ptr);
//     }
//
//     void free()
//     {
//         AllocatedDeferredBase<T, Manager>::free(this);
//     }
//
// protected:
//     void operator delete(void*)
//     {
//         BOOST_ASSERT( false );
//     }
//
// private:
//     struct Chunk
//     {
//         Allocator* alloc;
//         char       data[];
//     };
//
//     static void destroy(void* ptr)
//     {
//         cout << "AllocatedDeferredBase::destroy" << endl;
//         Chunk* chunk = static_cast<Chunk*>(ptr);
//         reinterpret_cast<T*>(chunk->data)->~T();
//     }
//     static void free(void* ptr)
//     {
//         cout << "AllocatedDeferredBase::free" << endl;
//         Chunk* chunk = static_cast<Chunk*>(ptr) - 1;
//         BOOST_ASSERT( chunk->data == ptr );
//         chunk->alloc->free(&destroy, chunk);
//     }
//
//     void* operator new(size_t);
// };

}; };

#endif // MESCALINE_MEMORY_MANAGER_HPP_INCLUDED
<commit_msg>Omit inclusion of <boost/lock_free/fifo.hpp><commit_after>#ifndef MESCALINE_MEMORY_MANAGER_HPP_INCLUDED
#define MESCALINE_MEMORY_MANAGER_HPP_INCLUDED

#include <Mescaline/Exception.hpp>
#include <Mescaline/Memory.hpp>

#include <boost/cstdint.hpp>
//#include <boost/lockfree/fifo.hpp>

namespace Mescaline { namespace Memory {

using namespace std;

class RTMemoryManager
{
public:
    // Primitives
    void* alloc(size_t numBytes)
        throw(MemoryAllocationFailure)
        { return Memory::alloc(numBytes); }
    template <size_t align> void* allocAligned(size_t numBytes)
        throw(MemoryAllocationFailure)
        { return Memory::allocAligned<align>(numBytes); }
    void free(void* ptr)
        throw(MemoryAllocationFailure)
        { Memory::free(ptr); }

    // Wrappers
    template <typename T> T* allocOf(size_t numElems=1)
        throw(MemoryAllocationFailure)
        { return Memory::allocOf<T>(numElems); }
    template <typename T, size_t align> T* allocAlignedOf(size_t numElems=1)
        throw(MemoryAllocationFailure)
        { return Memory::allocAligned<T,align>(numElems); }
};

template <class T, class Allocator, size_t align=kDefaultAlignment> class AllocatedBase
{
    struct Chunk
    {
        Allocator*  alloc;
        char        padding[MESCALINE_PADDING(align, sizeof(Allocator*))];
        char        data[];
    };

protected:
    static const size_t kAlignment = align;

    static void* alloc(Allocator& allocator, size_t size)
    {
        Chunk* chunk = static_cast<Chunk*>(allocator.allocAligned<align>(sizeof(Chunk) + size));
        chunk->alloc = &allocator;
        BOOST_ASSERT( MESCALINE_ISALIGNED(align, reinterpret_cast<size_t>(chunk->data)) );
        return chunk->data;
    }
    static void destroy(void* ptr)
    {
        cout << "AllocatedBase::free" << endl;
        Chunk* chunk = static_cast<Chunk*>(ptr) - 1;
        BOOST_ASSERT( chunk->data == ptr );
        static_cast<T*>(ptr)->~T();
        chunk->alloc->free(chunk);
    }

    void* operator new(size_t);
};

template <class T, class Allocator, size_t align=kDefaultAlignment> class Allocated
    : public AllocatedBase<T, Allocator, align>
{
    typedef AllocatedBase<T, Allocator, align> super;

public:
    void* operator new(size_t size, Allocator& alloc)
    {
        return super::alloc(alloc, size);
    }
    void operator delete(void* ptr, Allocator& alloc)
    {
        super::destroy(ptr);
    }
    void* operator new(size_t size, Allocator& alloc, size_t additional)
    {
        return super::alloc(alloc, size+additional);
    }
    void operator delete(void* ptr, Allocator& alloc, size_t realSize)
    {
        super::destroy(ptr);
    }
    void operator delete(void* ptr)
    {
        super::destroy(ptr);
    }
};

// template <class Manager> class DeferredMemoryManager
// {
// public:
//     typedef void (*Destructor)(void* ptr);
//
//     DeferredMemoryManager(Manager& mem)
//         : m_mem(mem)
//     { }
//
//     void* malloc(size_t size)
//     {
//         Chunk* chunk;
//         while (m_fifo.dequeue(chunk)) {
//             if (chunk->destroy != 0) {
//                 chunk->destroy(chunk->data);
//             }
//             m_mem.free(chunk);
//         }
//         cout << "DeferredMemoryManager::malloc" << endl;
//         chunk = static_cast<Chunk*>(m_mem.malloc(sizeof(Chunk) + size));
//         chunk->destroy = 0;
//         return chunk->data;
//     }
//     void free(Destructor destroy, void* ptr)
//     {
//         Chunk* chunk = static_cast<Chunk*>(ptr) - 1;
//         chunk->destroy = destroy;
//         do {
//             /* SPIN */
//         } while (!m_fifo.enqueue(chunk));
//     }
//
// private:
//     struct Chunk
//     {
//         Destructor  destroy;
//         char        data[];
//     };
//
//     Manager& m_mem;
//     boost::lockfree::fifo<Chunk*> m_fifo;
// };
//
// template <class T, class Manager> class AllocatedDeferredBase
// {
// public:
//     typedef DeferredMemoryManager<Manager> Allocator;
//
//     void* operator new(size_t size, Allocator& alloc)
//     {
//         Chunk* chunk = static_cast<Chunk*>(alloc.malloc(sizeof(Chunk) + size));
//         chunk->alloc = &alloc;
//         return chunk->data;
//     }
//     void operator delete(void* ptr, Allocator& alloc)
//     {
//         AllocatedDeferredBase<T, Manager>::free(ptr);
//     }
//
//     void free()
//     {
//         AllocatedDeferredBase<T, Manager>::free(this);
//     }
//
// protected:
//     void operator delete(void*)
//     {
//         BOOST_ASSERT( false );
//     }
//
// private:
//     struct Chunk
//     {
//         Allocator* alloc;
//         char       data[];
//     };
//
//     static void destroy(void* ptr)
//     {
//         cout << "AllocatedDeferredBase::destroy" << endl;
//         Chunk* chunk = static_cast<Chunk*>(ptr);
//         reinterpret_cast<T*>(chunk->data)->~T();
//     }
//     static void free(void* ptr)
//     {
//         cout << "AllocatedDeferredBase::free" << endl;
//         Chunk* chunk = static_cast<Chunk*>(ptr) - 1;
//         BOOST_ASSERT( chunk->data == ptr );
//         chunk->alloc->free(&destroy, chunk);
//     }
//
//     void* operator new(size_t);
// };

}; };

#endif // MESCALINE_MEMORY_MANAGER_HPP_INCLUDED
<|endoftext|>


<commit_before>/*****************************************************************************
 * generic_layout.cpp
 *****************************************************************************
 * Copyright (C) 2003 the VideoLAN team
 * $Id$
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
 *          Olivier Teulire <ipkiss@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

#include "generic_layout.hpp"
#include "top_window.hpp"
#include "os_factory.hpp"
#include "os_graphics.hpp"
#include "../controls/ctrl_generic.hpp"

GenericLayout::GenericLayout( intf_thread_t *pIntf, int width, int height,
                              int minWidth, int maxWidth, int minHeight,
                              int maxHeight ):
    SkinObject( pIntf ), m_pWindow( NULL ), m_width( width ),
    m_height( height ), m_minWidth( minWidth ), m_maxWidth( maxWidth ),
    m_minHeight( minHeight ), m_maxHeight( maxHeight )
{
    // Get the OSFactory
    OSFactory *pOsFactory = OSFactory::instance( getIntf() );
    // Create the graphics buffer
    m_pImage = pOsFactory->createOSGraphics( width, height );
}

GenericLayout::~GenericLayout()
{
    if( m_pImage )
    {
        delete m_pImage;
    }
}

void GenericLayout::setWindow( TopWindow *pWindow )
{
    m_pWindow = pWindow;
}

void GenericLayout::onControlCapture( const CtrlGeneric &rCtrl )
{
    // Just forward the request to the window
    TopWindow *pWindow = getWindow();
    if( pWindow )
    {
        pWindow->onControlCapture( rCtrl );
    }
}

void GenericLayout::onControlRelease( const CtrlGeneric &rCtrl )
{
    // Just forward the request to the window
    TopWindow *pWindow = getWindow();
    if( pWindow )
    {
        pWindow->onControlRelease( rCtrl );
    }
}

void GenericLayout::addControl( CtrlGeneric *pControl,
                                const Position &rPosition, int layer )
{
    if( pControl )
    {
        // Associate this layout to the control
        pControl->setLayout( this, rPosition );

        // Draw the control
        pControl->draw( *m_pImage, rPosition.getLeft(), rPosition.getTop() );

        // Add the control in the list.
        // This list must remain sorted by layer order
        list<LayeredControl>::iterator it;
        for( it = m_controlList.begin(); it != m_controlList.end(); it++ )
        {
            if( layer < (*it).m_layer )
            {
                m_controlList.insert( it, LayeredControl( pControl, layer ) );
                break;
            }
        }
        // If this control is in front of all the previous ones
        if( it == m_controlList.end() )
        {
            m_controlList.push_back( LayeredControl( pControl, layer ) );
        }
    }
    else
    {
        msg_Dbg( getIntf(), "Adding NULL control in the layout" );
    }
}

const list<LayeredControl> &GenericLayout::getControlList() const
{
    return m_controlList;
}

void GenericLayout::onControlUpdate( const CtrlGeneric &rCtrl,
                                     int width, int height,
                                     int xOffSet, int yOffSet )
{
    // The size is not valid, refresh the whole layout
    if( width <= 0 || height <= 0 )
    {
        refreshAll();
        return;
    }

    const Position *pPos = rCtrl.getPosition();
    if( pPos )
    {
        refreshRect( pPos->getLeft() + xOffSet,
                     pPos->getTop() + yOffSet,
                     width, height );
    }
}

void GenericLayout::resize( int width, int height )
{
    if( width == m_width && height == m_height )
    {
        return;
    }

    // Update the window size
    m_width = width;
    m_height = height;

    // Recreate a new image
    if( m_pImage )
    {
        delete m_pImage;
        OSFactory *pOsFactory = OSFactory::instance( getIntf() );
        m_pImage = pOsFactory->createOSGraphics( width, height );
    }

    // Notify all the controls that the size has changed and redraw them
    list<LayeredControl>::const_iterator iter;
    for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
    {
        (*iter).m_pControl->onResize();
        const Position *pPos = (*iter).m_pControl->getPosition();
        if( pPos )
        {
            (*iter).m_pControl->draw( *m_pImage, pPos->getLeft(),
                                      pPos->getTop() );
        }
    }

    // Resize and refresh the associated window
    TopWindow *pWindow = getWindow();
    if( pWindow )
    {
        // Resize the window
        pWindow->refresh( 0, 0, width, height );
        pWindow->resize( width, height );
        pWindow->refresh( 0, 0, width, height );

        // Change the shape of the window and redraw it
        pWindow->updateShape();
        pWindow->refresh( 0, 0, width, height );
    }
}

void GenericLayout::refreshAll()
{
    refreshRect( 0, 0, m_width, m_height );
}

void GenericLayout::refreshRect( int x, int y, int width, int height )
{
    // Draw all the controls of the layout
    list<LayeredControl>::const_iterator iter;
    list<LayeredControl>::const_iterator iterVideo = m_controlList.end();
    for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
    {
        CtrlGeneric *pCtrl = (*iter).m_pControl;
        const Position *pPos = pCtrl->getPosition();
        if( pCtrl->isVisible() && pPos )
        {
            pCtrl->draw( *m_pImage, pPos->getLeft(), pPos->getTop() );
            // Remember the video control (we assume there is at most one video
            // control per layout)
            if( pCtrl->getType() == "video" && pCtrl->getPosition() )
                iterVideo = iter;
        }
    }

    // Refresh the associated window
    TopWindow *pWindow = getWindow();
    if( pWindow )
    {
        // Check boundaries
        if( x < 0 )
            x = 0;
        if( y < 0)
            y = 0;
        if( x + width > m_width )
            width = m_width - x;
        if( y + height > m_height )
            height = m_height - y;

        // Refresh the window... but do not paint on a video control!
        if( iterVideo == m_controlList.end() )
        {
            // No video control, we can safely repain the rectangle
            pWindow->refresh( x, y, width, height );
        }
        else
        {
            // Bad luck, there is a video control somewhere (not necessarily
            // in the repainting zone, btw).
            // We will divide the repainting into 4 regions (top, left, bottom
            // and right). The overlapping parts (i.e. the corners) of these
            // regions will be painted twice, because otherwise the algorithm
            // becomes a real mess :)

            // Use short variable names for convenience
            int xx = iterVideo->m_pControl->getPosition()->getLeft();
            int yy = iterVideo->m_pControl->getPosition()->getTop();
            int ww = iterVideo->m_pControl->getPosition()->getWidth();
            int hh = iterVideo->m_pControl->getPosition()->getHeight();

            // Top part:
            if( y < yy )
                pWindow->refresh( x, y, width, yy - y );
            // Left part:
            if( x < xx )
                pWindow->refresh( x, y, xx - x, height );
            // Bottom part
            if( y + height > yy + hh )
                pWindow->refresh( x, yy + hh, width, y + height - (yy + hh) );
            // Right part
            if( x + width > xx + ww )
                pWindow->refresh( xx + ww, y, x + width - (xx + ww), height );
        }
    }
}

const list<Anchor*>& GenericLayout::getAnchorList() const
{
    return m_anchorList;
}

void GenericLayout::addAnchor( Anchor *pAnchor )
{
    m_anchorList.push_back( pAnchor );
}

<commit_msg> * skins/src/generic_layout.cpp: Fixed a typo in a comment<commit_after>/*****************************************************************************
 * generic_layout.cpp
 *****************************************************************************
 * Copyright (C) 2003 the VideoLAN team
 * $Id$
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
 *          Olivier Teulire <ipkiss@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

#include "generic_layout.hpp"
#include "top_window.hpp"
#include "os_factory.hpp"
#include "os_graphics.hpp"
#include "../controls/ctrl_generic.hpp"

GenericLayout::GenericLayout( intf_thread_t *pIntf, int width, int height,
                              int minWidth, int maxWidth, int minHeight,
                              int maxHeight ):
    SkinObject( pIntf ), m_pWindow( NULL ), m_width( width ),
    m_height( height ), m_minWidth( minWidth ), m_maxWidth( maxWidth ),
    m_minHeight( minHeight ), m_maxHeight( maxHeight )
{
    // Get the OSFactory
    OSFactory *pOsFactory = OSFactory::instance( getIntf() );
    // Create the graphics buffer
    m_pImage = pOsFactory->createOSGraphics( width, height );
}

GenericLayout::~GenericLayout()
{
    if( m_pImage )
    {
        delete m_pImage;
    }
}

void GenericLayout::setWindow( TopWindow *pWindow )
{
    m_pWindow = pWindow;
}

void GenericLayout::onControlCapture( const CtrlGeneric &rCtrl )
{
    // Just forward the request to the window
    TopWindow *pWindow = getWindow();
    if( pWindow )
    {
        pWindow->onControlCapture( rCtrl );
    }
}

void GenericLayout::onControlRelease( const CtrlGeneric &rCtrl )
{
    // Just forward the request to the window
    TopWindow *pWindow = getWindow();
    if( pWindow )
    {
        pWindow->onControlRelease( rCtrl );
    }
}

void GenericLayout::addControl( CtrlGeneric *pControl,
                                const Position &rPosition, int layer )
{
    if( pControl )
    {
        // Associate this layout to the control
        pControl->setLayout( this, rPosition );

        // Draw the control
        pControl->draw( *m_pImage, rPosition.getLeft(), rPosition.getTop() );

        // Add the control in the list.
        // This list must remain sorted by layer order
        list<LayeredControl>::iterator it;
        for( it = m_controlList.begin(); it != m_controlList.end(); it++ )
        {
            if( layer < (*it).m_layer )
            {
                m_controlList.insert( it, LayeredControl( pControl, layer ) );
                break;
            }
        }
        // If this control is in front of all the previous ones
        if( it == m_controlList.end() )
        {
            m_controlList.push_back( LayeredControl( pControl, layer ) );
        }
    }
    else
    {
        msg_Dbg( getIntf(), "Adding NULL control in the layout" );
    }
}

const list<LayeredControl> &GenericLayout::getControlList() const
{
    return m_controlList;
}

void GenericLayout::onControlUpdate( const CtrlGeneric &rCtrl,
                                     int width, int height,
                                     int xOffSet, int yOffSet )
{
    // The size is not valid, refresh the whole layout
    if( width <= 0 || height <= 0 )
    {
        refreshAll();
        return;
    }

    const Position *pPos = rCtrl.getPosition();
    if( pPos )
    {
        refreshRect( pPos->getLeft() + xOffSet,
                     pPos->getTop() + yOffSet,
                     width, height );
    }
}

void GenericLayout::resize( int width, int height )
{
    if( width == m_width && height == m_height )
    {
        return;
    }

    // Update the window size
    m_width = width;
    m_height = height;

    // Recreate a new image
    if( m_pImage )
    {
        delete m_pImage;
        OSFactory *pOsFactory = OSFactory::instance( getIntf() );
        m_pImage = pOsFactory->createOSGraphics( width, height );
    }

    // Notify all the controls that the size has changed and redraw them
    list<LayeredControl>::const_iterator iter;
    for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
    {
        (*iter).m_pControl->onResize();
        const Position *pPos = (*iter).m_pControl->getPosition();
        if( pPos )
        {
            (*iter).m_pControl->draw( *m_pImage, pPos->getLeft(),
                                      pPos->getTop() );
        }
    }

    // Resize and refresh the associated window
    TopWindow *pWindow = getWindow();
    if( pWindow )
    {
        // Resize the window
        pWindow->refresh( 0, 0, width, height );
        pWindow->resize( width, height );
        pWindow->refresh( 0, 0, width, height );

        // Change the shape of the window and redraw it
        pWindow->updateShape();
        pWindow->refresh( 0, 0, width, height );
    }
}

void GenericLayout::refreshAll()
{
    refreshRect( 0, 0, m_width, m_height );
}

void GenericLayout::refreshRect( int x, int y, int width, int height )
{
    // Draw all the controls of the layout
    list<LayeredControl>::const_iterator iter;
    list<LayeredControl>::const_iterator iterVideo = m_controlList.end();
    for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
    {
        CtrlGeneric *pCtrl = (*iter).m_pControl;
        const Position *pPos = pCtrl->getPosition();
        if( pCtrl->isVisible() && pPos )
        {
            pCtrl->draw( *m_pImage, pPos->getLeft(), pPos->getTop() );
            // Remember the video control (we assume there is at most one video
            // control per layout)
            if( pCtrl->getType() == "video" && pCtrl->getPosition() )
                iterVideo = iter;
        }
    }

    // Refresh the associated window
    TopWindow *pWindow = getWindow();
    if( pWindow )
    {
        // Check boundaries
        if( x < 0 )
            x = 0;
        if( y < 0)
            y = 0;
        if( x + width > m_width )
            width = m_width - x;
        if( y + height > m_height )
            height = m_height - y;

        // Refresh the window... but do not paint on a video control!
        if( iterVideo == m_controlList.end() )
        {
            // No video control, we can safely repaint the rectangle
            pWindow->refresh( x, y, width, height );
        }
        else
        {
            // Bad luck, there is a video control somewhere (not necessarily
            // in the repainting zone, btw).
            // We will divide the repainting into 4 regions (top, left, bottom
            // and right). The overlapping parts (i.e. the corners) of these
            // regions will be painted twice, because otherwise the algorithm
            // becomes a real mess :)

            // Use short variable names for convenience
            int xx = iterVideo->m_pControl->getPosition()->getLeft();
            int yy = iterVideo->m_pControl->getPosition()->getTop();
            int ww = iterVideo->m_pControl->getPosition()->getWidth();
            int hh = iterVideo->m_pControl->getPosition()->getHeight();

            // Top part:
            if( y < yy )
                pWindow->refresh( x, y, width, yy - y );
            // Left part:
            if( x < xx )
                pWindow->refresh( x, y, xx - x, height );
            // Bottom part
            if( y + height > yy + hh )
                pWindow->refresh( x, yy + hh, width, y + height - (yy + hh) );
            // Right part
            if( x + width > xx + ww )
                pWindow->refresh( xx + ww, y, x + width - (xx + ww), height );
        }
    }
}

const list<Anchor*>& GenericLayout::getAnchorList() const
{
    return m_anchorList;
}

void GenericLayout::addAnchor( Anchor *pAnchor )
{
    m_anchorList.push_back( pAnchor );
}

<|endoftext|>


<commit_before>#pragma once

#include <utility>
#include <memory>
#include <uv.h>
#include "emitter.hpp"
#include "loop.hpp"

namespace uvw {

/**
 * @brief Common class for almost all the resources available in `uvw`.
 *
 * This is the base class for handles and requests.

 * It mainly acts as a wrapper around a libuv's data structure.
 */
template<typename T, typename U>
class Resource: public Emitter<T>, public std::enable_shared_from_this<T> {
    template<typename, typename>
    friend class Resource;

protected:
    explicit Resource(std::shared_ptr<Loop> ref)
        : Emitter<T>{},
          std::enable_shared_from_this<T>{},
          pLoop{std::move(ref)},
          resource{}
    {
        resource.data = static_cast<T*>(this);
    }

    auto parent() const noexcept {
        return pLoop->loop.get();
    }

    auto get() noexcept {
        return &resource;
    }

    const auto get() const noexcept {
        return &resource;
    }

    template<typename R>
    auto get() noexcept {
        static_assert(not std::is_same<R, U>::value, "!");
        return reinterpret_cast<R*>(&resource);
    }

    template<typename R>
    auto get() const noexcept {
        static_assert(not std::is_same<R, U>::value, "!");
        return reinterpret_cast<const R*>(&resource);
    }

    void leak() noexcept {
        ptr = this->shared_from_this();
    }

    void reset() noexcept {
        ptr.reset();
    }

    bool self() const noexcept {
        return static_cast<bool>(ptr);
    }

public:
    Resource(const Resource &) = delete;
    Resource(Resource &&) = delete;

    virtual ~Resource() {
        static_assert(std::is_base_of<Resource<T, U>, T>::value, "!");
    }

    Resource& operator=(const Resource &) = delete;
    Resource& operator=(Resource &&) = delete;

    /**
     * @brief Gets the loop from which the resource was originated.
     * @return A reference to a loop instance.
     */
    Loop& loop() const noexcept { return *pLoop; }

private:
    std::shared_ptr<void> ptr{nullptr};
    std::shared_ptr<Loop> pLoop;
    U resource;
};

}
<commit_msg>minor changes<commit_after>#pragma once

#include <utility>
#include <memory>
#include <uv.h>
#include "emitter.hpp"
#include "loop.hpp"

namespace uvw {

/**
 * @brief Common class for almost all the resources available in `uvw`.
 *
 * This is the base class for handles and requests.

 * It mainly acts as a wrapper around a libuv's data structure.
 */
template<typename T, typename U>
class Resource: public Emitter<T>, public std::enable_shared_from_this<T> {
    template<typename, typename>
    friend class Resource;

protected:
    explicit Resource(std::shared_ptr<Loop> ref)
        : Emitter<T>{},
          std::enable_shared_from_this<T>{},
          pLoop{std::move(ref)},
          resource{}
    {
        resource.data = static_cast<T*>(this);
    }

    auto parent() const noexcept {
        return pLoop->loop.get();
    }

    auto get() noexcept {
        return &resource;
    }

    auto get() const noexcept {
        return const_cast<const U *>(&resource);
    }

    template<typename R>
    auto get() noexcept {
        static_assert(not std::is_same<R, U>::value, "!");
        return reinterpret_cast<R*>(&resource);
    }

    template<typename R>
    auto get() const noexcept {
        static_assert(not std::is_same<R, U>::value, "!");
        return reinterpret_cast<const R*>(&resource);
    }

    void leak() noexcept {
        ptr = this->shared_from_this();
    }

    void reset() noexcept {
        ptr.reset();
    }

    bool self() const noexcept {
        return static_cast<bool>(ptr);
    }

public:
    Resource(const Resource &) = delete;
    Resource(Resource &&) = delete;

    virtual ~Resource() {
        static_assert(std::is_base_of<Resource<T, U>, T>::value, "!");
    }

    Resource& operator=(const Resource &) = delete;
    Resource& operator=(Resource &&) = delete;

    /**
     * @brief Gets the loop from which the resource was originated.
     * @return A reference to a loop instance.
     */
    Loop& loop() const noexcept { return *pLoop; }

private:
    std::shared_ptr<void> ptr{nullptr};
    std::shared_ptr<Loop> pLoop;
    U resource;
};

}
<|endoftext|>


<commit_before>// Copyright 2018 Global Phasing Ltd.
//
// Handles of "gemmi validate --monomer".
// Part of gemmi-validate that does extra validation for cif files from
// Refmac monomer dictionary.

#include <iostream>
#include <stdexcept>
#include "gemmi/chemcomp.hpp"

namespace cif = gemmi::cif;
using gemmi::Restraints;

static void check_valency(const gemmi::ChemComp& cc) {
  for (const gemmi::ChemComp::Atom& atom : cc.atoms) {
    if (cc.atoms.size() == 1)
      continue;
    float valency = 0.0f;
    for (const Restraints::Bond& bond : cc.rt.bonds)
      if (bond.id1 == atom.id || bond.id2 == atom.id)
        valency += order_of_bond_type(bond.type);
    bool ok = valency >= 0.5f;
    valency -= atom.charge;
    if (atom.is_hydrogen()) {
      ok = std::round(valency) == 1.0;
    } else if (atom.el == gemmi::El::P) {
      ok = (valency == 3.0f || valency == 5.0f || valency == 5.5f);
    }
    if (!ok)
      std::cout << cc.name << ": " << atom.id << " (" << element_name(atom.el)
                << ") has bond order " << valency << std::endl;
  }
}

static std::string repr(const Restraints::Angle& angle) {
  return angle.id1.atom + "-" + angle.id2.atom + "-" + angle.id3.atom;
}
static std::string repr(const Restraints::Torsion& tor) {
  return tor.id1.atom + "-" + tor.id2.atom + "-" +
         tor.id3.atom + "-" + tor.id4.atom;
}

static void check_bond_angle_consistency(const gemmi::ChemComp& cc) {
  for (const Restraints::Angle& angle : cc.rt.angles) {
    if (!cc.rt.are_bonded(angle.id1, angle.id2) ||
        !cc.rt.are_bonded(angle.id2, angle.id3))
      std::cout << cc.name << ": angle " << repr(angle) << " not bonded"
                << std::endl;
    if (angle.value < 20)
      std::cout << cc.name << ": angle " << repr(angle)
                << " with low value: " << angle.value << std::endl;
  }
  for (const Restraints::Torsion& tor : cc.rt.torsions) {
    if (!cc.rt.are_bonded(tor.id1, tor.id2) ||
        !cc.rt.are_bonded(tor.id2, tor.id3) ||
        !cc.rt.are_bonded(tor.id3, tor.id4))
      std::cout << cc.name << ": torsion " << repr(tor) << " not bonded"
                << std::endl;
  }
}

void check_monomer_doc(const cif::Document& doc) {
  for (const cif::Block& block : doc.blocks)
    if (block.name != "comp_list") {
      try {
        gemmi::ChemComp cc = gemmi::make_chemcomp_from_block(block);
        check_valency(cc);
        check_bond_angle_consistency(cc);
      } catch (const std::exception& e) {
        std::cerr << "Failed to interpret " << block.name << " from "
                  << doc.source << ":\n " << e.what() << std::endl;
      }
    }
}

// vim:sw=2:ts=2:et:path^=../include,../third_party
<commit_msg>gemmi-validate: check _chem_comp_atom.x/y/z<commit_after>// Copyright 2018 Global Phasing Ltd.
//
// Handles of "gemmi validate --monomer".
// Part of gemmi-validate that does extra validation for cif files from
// Refmac monomer dictionary.

#include <iostream>
#include <stdexcept>
#include "gemmi/cifdoc.hpp"
#include "gemmi/chemcomp.hpp"
#include "gemmi/calculate.hpp" // for calculate_angle

namespace cif = gemmi::cif;
using gemmi::Restraints;
using gemmi::Topo;

// some rules for the number of bonds (currently only for H and P)
static void check_valency(const gemmi::ChemComp& cc) {
  for (const gemmi::ChemComp::Atom& atom : cc.atoms) {
    if (cc.atoms.size() == 1)
      continue;
    float valency = 0.0f;
    for (const Restraints::Bond& bond : cc.rt.bonds)
      if (bond.id1 == atom.id || bond.id2 == atom.id)
        valency += order_of_bond_type(bond.type);
    bool ok = valency >= 0.5f;
    valency -= atom.charge;
    if (atom.is_hydrogen()) {
      ok = std::round(valency) == 1.0;
    } else if (atom.el == gemmi::El::P) {
      ok = (valency == 3.0f || valency == 5.0f || valency == 5.5f);
    }
    if (!ok)
      std::cout << cc.name << ": " << atom.id << " (" << element_name(atom.el)
                << ") has bond order " << valency << std::endl;
  }
}

static std::string repr(const Restraints::Bond& bond) {
  return bond.id1.atom + "-" + bond.id2.atom;
}
static std::string repr(const Restraints::Angle& angle) {
  return angle.id1.atom + "-" + angle.id2.atom + "-" + angle.id3.atom;
}
static std::string repr(const Restraints::Torsion& tor) {
  return tor.id1.atom + "-" + tor.id2.atom + "-" +
         tor.id3.atom + "-" + tor.id4.atom;
}

static void check_bond_angle_consistency(const gemmi::ChemComp& cc) {
  for (const Restraints::Angle& angle : cc.rt.angles) {
    if (!cc.rt.are_bonded(angle.id1, angle.id2) ||
        !cc.rt.are_bonded(angle.id2, angle.id3))
      std::cout << cc.name << ": angle " << repr(angle) << " not bonded"
                << std::endl;
    if (angle.value < 20)
      std::cout << cc.name << ": angle " << repr(angle)
                << " with low value: " << angle.value << std::endl;
  }
  for (const Restraints::Torsion& tor : cc.rt.torsions) {
    if (!cc.rt.are_bonded(tor.id1, tor.id2) ||
        !cc.rt.are_bonded(tor.id2, tor.id3) ||
        !cc.rt.are_bonded(tor.id3, tor.id4))
      std::cout << cc.name << ": torsion " << repr(tor) << " not bonded"
                << std::endl;
  }
}

gemmi::Residue read_chem_comp_atom_as_residue(const cif::Block& block) {
  gemmi::Residue res;
  res.name = block.name;
  cif::Table table = const_cast<cif::Block&>(block).find(
      "_chem_comp_atom.", {"atom_id", "type_symbol", "x", "y", "z"});
  res.atoms.resize(table.length());
  int n = 0;
  for (auto row : table) {
    gemmi::Atom& atom = res.atoms[n++];
    atom.name = row.str(0);
    atom.element = gemmi::Element(row.str(1));
    atom.pos = gemmi::Position(cif::as_number(row[2]),
                               cif::as_number(row[3]),
                               cif::as_number(row[4]));
  }
  return res;
}

static double angle_abs_diff(double a, double b) {
  double d = std::abs(a - b);
  return d > 180 ? std::abs(d - 360.) : d;
}

// check _chem_comp_atom.x/y/z
static void check_xyz_consistency(const gemmi::ChemComp& cc,
                                  const cif::Block& block) {
  gemmi::Residue res = read_chem_comp_atom_as_residue(block);
  Topo topo;
  topo.chains.resize(1);
  Topo::ResInfo ri(&res);
  ri.chemcomp = cc;
  topo.apply_internal_restraints_to_residue(ri);
  topo.chains[0].residues.push_back(ri);
  for (const Topo::Bond& t : topo.bonds) {
    double value = t.calculate();
    if (std::abs(value - t.restr->value) > t.restr->esd)
      std::cout << " [xyz bond] " << repr(*t.restr) << " should be "
                << t.restr->value << " (esd " << t.restr->esd << ") but is "
                << value << std::endl;
  }
  for (const Topo::Angle& t : topo.angles) {
    double value = gemmi::deg(t.calculate());
    if (angle_abs_diff(value, t.restr->value) > t.restr->esd)
      std::cout << " [xyz angle] " << repr(*t.restr) << " should be "
                << t.restr->value << " (esd " << t.restr->esd << ") but is "
                << value << std::endl;
  }
  for (const Topo::Torsion& t : topo.torsions) {
    double value = gemmi::deg(t.calculate());
    if (angle_abs_diff(value, t.restr->value) > t.restr->esd)
      std::cout << " [xyz torsion] " << repr(*t.restr) << " should be "
                << t.restr->value << " (esd " << t.restr->esd << ") but is "
                << value << std::endl;
  }
  // TODO chiral, plane
}

void check_monomer_doc(const cif::Document& doc) {
  for (const cif::Block& block : doc.blocks)
    if (block.name != "comp_list") {
      try {
        gemmi::ChemComp cc = gemmi::make_chemcomp_from_block(block);
        check_valency(cc);
        check_bond_angle_consistency(cc);
        check_xyz_consistency(cc, block);
      } catch (const std::exception& e) {
        std::cerr << "Failed to interpret " << block.name << " from "
                  << doc.source << ":\n " << e.what() << std::endl;
      }
    }
}

// vim:sw=2:ts=2:et:path^=../include,../third_party
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>

#include "Game.h"
#include "MyException.h"
#include "Engine.h"
#include "ResourceManager.h"

Game::Game()
: _screenWidth(1366)
, _screenHeight(768)
, _gameState(GameState::PLAY)
, _camera(_screenWidth, _screenHeight) {}

Game::~Game()
{
}

void Game::run() {
	initSystems();
	_map.init();
	gameLoop();
}

void Game::initSystems() {
	Engine::init();
	_window.create("Alpha Game Engine", _screenWidth, _screenHeight, /*0);//*/Engine::WindowFlags::FULLSCREEN);
	int screenWidth = _window.getScreenWidth();
	int screenHeight = _window.getScreenHeight();

	std::cout << "Width: " << screenWidth << " Height: " << screenHeight << std::endl;
	//updateResolution(screenWidth, screenHeight);
	initShaders();
	_spriteBatch.init();
}

void Game::updateResolution(int screenWidth, int screenHeight) {
	_screenWidth = screenWidth;
	_screenHeight = screenHeight;
	_camera.updateResolution(_screenWidth, _screenHeight);
}

void Game::initShaders() {
	_colorProgram.compileShaders("shaders/colorShading.vert", "shaders/colorShading.frag");
	_colorProgram.addAttribute("vertexPosition");
	_colorProgram.addAttribute("vertexColor");
	_colorProgram.addAttribute("vertexUV");
	_colorProgram.linkShaders();
}

void Game::gameLoop() {

	float dt = _time.getFrameCap();
	while (_gameState != GameState::EXIT) {
		_time.begin();
		processInput();
		_map.update(dt);
		_camera.update();
		draw();

		dt = _time.end();
	}
}

void Game::processInput() {
	SDL_Event event;

	const float CAMERA_SPEED = 4.0f;

	//Will keep looping until there are no more events to process
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
			case SDL_QUIT:
				_gameState = GameState::EXIT;
				break;
			case SDL_MOUSEMOTION:
				_inputManager.setMouseCoords(event.motion.x, event.motion.y);
				break;
			case SDL_KEYDOWN:
				_inputManager.pressKey(event.key.keysym.sym);
				break;
			case SDL_KEYUP:
				_inputManager.releaseKey(event.key.keysym.sym);
				break;
			case SDL_MOUSEBUTTONDOWN:
				_inputManager.pressKey(event.button.button);
				break;
			case SDL_MOUSEBUTTONUP:
				_inputManager.releaseKey(event.button.button);
				break;
		}
	}

	glm::vec2 mouseCoords = _inputManager.getMouseCoords();
	glm::vec2 worldCoords = _camera.convertScreenToWorld(mouseCoords);
	//std::cout << "X: " << mouseCoords.x << " Y: " << mouseCoords.y << std::endl;

	glm::vec2 lowerBounds = 0.1f * glm::vec2(_screenWidth, _screenHeight);
	glm::vec2 upperBounds = 0.9f * glm::vec2(_screenWidth, _screenHeight);

	glm::vec4 mapBounds = _map.getBounds();
	glm::vec2 cameraPosition = _camera.getPosition();

	if (mouseCoords.x <  lowerBounds.x && mapBounds.x < cameraPosition.x - 0.5f * _screenWidth) {
		_camera.setPosition(_camera.getPosition() + glm::vec2(-CAMERA_SPEED, 0.0f));
	}
	if (mouseCoords.x > upperBounds.x && mapBounds.z > cameraPosition.x + 0.5f * _screenWidth) {
		_camera.setPosition(_camera.getPosition() + glm::vec2(CAMERA_SPEED, 0.0f));
	}
	if (mouseCoords.y < lowerBounds.y && mapBounds.w > cameraPosition.y + 0.5f * _screenHeight) {
		_camera.setPosition(_camera.getPosition() + glm::vec2(0.0f, CAMERA_SPEED));
	}
	if (mouseCoords.y > upperBounds.y && mapBounds.y < cameraPosition.y - 0.5f * _screenHeight) {
		_camera.setPosition(_camera.getPosition() + glm::vec2(0.0f, -CAMERA_SPEED));
	}

	if (_inputManager.isKeyPressed(SDLK_ESCAPE)) {
		_interface.clearTargets();
	}
	if (_inputManager.isKeyPressed(SDL_BUTTON_LEFT)) {
		_interface.updateBox(worldCoords);
	}
	else if (_interface.getBoxActive()) {
		bool append = _inputManager.isKeyPressed(SDLK_LSHIFT);
		_interface.updateTargets(_map, append);
	}
	if (_inputManager.isKeyPressed(SDL_BUTTON_RIGHT)) {
		_interface.setTargetsDestination(_map, worldCoords);
	}

}

void Game::draw() {
	const unsigned int TEXTURE_UNIT = 0;
	glClearDepth(1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	_colorProgram.use();

	glActiveTexture(GL_TEXTURE0);

	GLuint textureLocation = _colorProgram.getUniformLocation("tex");
	glUniform1i(textureLocation, TEXTURE_UNIT);

	GLuint pLocation = _colorProgram.getUniformLocation("P");
	glm::mat4 cameraMatrix = _camera.getCameraMatrix();

	glUniformMatrix4fv(pLocation, 1, GL_FALSE, &(cameraMatrix[0][0]));

	_spriteBatch.begin();

	_map.draw(_spriteBatch);
	_interface.draw(_spriteBatch);

	_spriteBatch.end();
	_spriteBatch.renderBatch();

	glBindTexture(GL_TEXTURE_2D,  0);
	_colorProgram.unuse();

	_window.swapBuffer();
}<commit_msg>Changed formatting.<commit_after>#include <algorithm>
#include <iostream>

#include "Game.h"
#include "MyException.h"
#include "Engine.h"
#include "ResourceManager.h"

Game::Game()
: _screenWidth(1366)
, _screenHeight(768)
, _gameState(GameState::PLAY)
, _camera(_screenWidth, _screenHeight) {}

Game::~Game()
{
}

void Game::run() {
	initSystems();
	_map.init();
	gameLoop();
}

void Game::initSystems() {
	Engine::init();
	_window.create("Alpha Game Engine", _screenWidth, _screenHeight, /*0);//*/Engine::WindowFlags::FULLSCREEN);
	int screenWidth = _window.getScreenWidth();
	int screenHeight = _window.getScreenHeight();

	std::cout << "Width: " << screenWidth << " Height: " << screenHeight << std::endl;
	//updateResolution(screenWidth, screenHeight);
	initShaders();
	_spriteBatch.init();
}

void Game::updateResolution(int screenWidth, int screenHeight) {
	_screenWidth = screenWidth;
	_screenHeight = screenHeight;
	_camera.updateResolution(_screenWidth, _screenHeight);
}

void Game::initShaders() {
	_colorProgram.compileShaders("shaders/colorShading.vert", "shaders/colorShading.frag");
	_colorProgram.addAttribute("vertexPosition");
	_colorProgram.addAttribute("vertexColor");
	_colorProgram.addAttribute("vertexUV");
	_colorProgram.linkShaders();
}

void Game::gameLoop() {

	float dt = _time.getFrameCap();
	while (_gameState != GameState::EXIT) {
		_time.begin();
		processInput();
		_map.update(dt);
		_camera.update();
		draw();

		dt = _time.end();
	}
}

void Game::processInput() {
	SDL_Event event;

	const float CAMERA_SPEED = 4.0f;

	//Will keep looping until there are no more events to process
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
			case SDL_QUIT:
				_gameState = GameState::EXIT;
				break;
			case SDL_MOUSEMOTION:
				_inputManager.setMouseCoords(event.motion.x, event.motion.y);
				break;
			case SDL_KEYDOWN:
				_inputManager.pressKey(event.key.keysym.sym);
				break;
			case SDL_KEYUP:
				_inputManager.releaseKey(event.key.keysym.sym);
				break;
			case SDL_MOUSEBUTTONDOWN:
				_inputManager.pressKey(event.button.button);
				break;
			case SDL_MOUSEBUTTONUP:
				_inputManager.releaseKey(event.button.button);
				break;
		}
	}

	glm::vec2 mouseCoords = _inputManager.getMouseCoords();
	glm::vec2 worldCoords = _camera.convertScreenToWorld(mouseCoords);
	//std::cout << "X: " << mouseCoords.x << " Y: " << mouseCoords.y << std::endl;

	glm::vec2 lowerBounds = 0.1f * glm::vec2(_screenWidth, _screenHeight);
	glm::vec2 upperBounds = 0.9f * glm::vec2(_screenWidth, _screenHeight);

	glm::vec4 mapBounds = _map.getBounds();
	glm::vec2 cameraPosition = _camera.getPosition();

	if (mouseCoords.x <  lowerBounds.x && mapBounds.x < cameraPosition.x - 0.5f * _screenWidth) {
		_camera.setPosition(_camera.getPosition() + glm::vec2(-CAMERA_SPEED, 0.0f));
	}
	if (mouseCoords.x > upperBounds.x && mapBounds.z > cameraPosition.x + 0.5f * _screenWidth) {
		_camera.setPosition(_camera.getPosition() + glm::vec2(CAMERA_SPEED, 0.0f));
	}
	if (mouseCoords.y < lowerBounds.y && mapBounds.w > cameraPosition.y + 0.5f * _screenHeight) {
		_camera.setPosition(_camera.getPosition() + glm::vec2(0.0f, CAMERA_SPEED));
	}
	if (mouseCoords.y > upperBounds.y && mapBounds.y < cameraPosition.y - 0.5f * _screenHeight) {
		_camera.setPosition(_camera.getPosition() + glm::vec2(0.0f, -CAMERA_SPEED));
	}

	if (_inputManager.isKeyPressed(SDLK_ESCAPE)) {
		_interface.clearTargets();
	}
	if (_inputManager.isKeyPressed(SDL_BUTTON_LEFT)) {
		_interface.updateBox(worldCoords);
	}
	else if (_interface.getBoxActive()) {
		bool append = _inputManager.isKeyPressed(SDLK_LSHIFT);
		_interface.updateTargets(_map, append);
	}
	if (_inputManager.isKeyPressed(SDL_BUTTON_RIGHT)) {
		_interface.setTargetsDestination(_map, worldCoords);
	}

}

void Game::draw() {
	const unsigned int TEXTURE_UNIT = 0;
	glClearDepth(1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	_colorProgram.use();

	glActiveTexture(GL_TEXTURE0);

	GLuint textureLocation = _colorProgram.getUniformLocation("tex");
	glUniform1i(textureLocation, TEXTURE_UNIT);

	GLuint pLocation = _colorProgram.getUniformLocation("P");
	glm::mat4 cameraMatrix = _camera.getCameraMatrix();

	glUniformMatrix4fv(pLocation, 1, GL_FALSE, &(cameraMatrix[0][0]));

	_spriteBatch.begin();

	_map.draw(_spriteBatch);
	_interface.draw(_spriteBatch);

	_spriteBatch.end();
	_spriteBatch.renderBatch();

	glBindTexture(GL_TEXTURE_2D,  0);
	_colorProgram.unuse();

	_window.swapBuffer();
}
<|endoftext|>


<commit_before>/*
    options.hpp - Support file for writing LV2 plugins in C++

    Copyright (C) 2013 Michael Fisher <mfisher31@gmail.com>

    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.

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307  USA
*/

/** @file options.hpp
    LV2 Compatibility: LV2 Options v1.0 (2012-10-14)
 */

#ifndef LVTK_OPTIONS_HPP
#define LVTK_OPTIONS_HPP

#include <lv2/lv2plug.in/ns/ext/options/options.h>

#ifndef LVTK_OPTIONS_IFACE
#define LVTK_OPTIONS_IFACE 1
#endif

namespace lvtk {

    /** Convenience enum to get LV2_Options_Option into a C++ namespace */
    typedef LV2_Options_Option Option;

    /** Convenience enum to get LV2_Options_Context into a C++ namespace */
    typedef enum {
        /** This option applies to the instance itself.  The subject must be
            ignored. */
        OPTIONS_INSTANCE    = LV2_OPTIONS_INSTANCE,

        /** This option applies to some named resource.  The subject is a URI mapped
            to an integer (a LV2_URID, like the key) */
        OPTIONS_RESOURCE    = LV2_OPTIONS_RESOURCE,

        /** This option applies to some blank node.  The subject is a blank node
            identifier, which is valid only within the current local scope. */
        OPTIONS_BLANK       = LV2_OPTIONS_BLANK,

        /** This option applies to a port on the instance.  The subject is the
            port's index. */
        OPTIONS_PORT        = LV2_OPTIONS_PORT
    } OptionsContext;

    /** Convenience enum to get LV2_Options_Status into a C++ namespace */
    typedef enum {
        OPTIONS_SUCCESS         = LV2_OPTIONS_SUCCESS,          /**< Completed successfully. */
        OPTIONS_ERR_UNKNOWN     = LV2_OPTIONS_ERR_UNKNOWN,      /**< Unknown error. */
        OPTIONS_ERR_BAD_SUBJECT = LV2_OPTIONS_ERR_BAD_SUBJECT,  /**< Invalid/unsupported subject. */
        OPTIONS_ERR_BAD_KEY     = LV2_OPTIONS_ERR_BAD_KEY,      /**< Invalid/unsupported key. */
        OPTIONS_ERR_BAD_VALUE   = LV2_OPTIONS_ERR_BAD_VALUE     /**< Invalid/unsupported value. */
    } OptionsStatus;

    class OptionsIter
    {
    public:

        OptionsIter (const Option* options)
            : index (0),m_size (0), p_opts (options)
        {
            while (0 != next())
                ++m_size;
            index = 0;
        }

        /** */
        const Option* next()
        {
            if (p_opts == NULL || (p_opts[index].key   == 0 &&
                                   p_opts[index].value == 0))
                return 0;

            return &p_opts[index++];
        }

        uint32_t size()     const       { return m_size; }

    private:

        /** @internal The current option index */
        uint32_t           index;

        /** @internal The number of options in the array */
        uint32_t           m_size;

        /** @internal Non constant iteration pointer */
        const Option*      p_opts;

    };

    /** The LV2 Options Feature Mixin

        This mixin provides a callback handler for the LV2 Options feature and
        hooks up the LV2_Options_Interface as extension data.

        @struct lvtk::Options lvtk/ext/options.hpp
        @ingroup pluginmixins
        @ingroup guimixins
     */
    template <bool Required = false>
    struct Options
    {

        template <class Derived>
        struct I : Extension<Required>
        {

            /** @skip */
            I() : p_supplied_opts (NULL) { }

            /** @skip */
            static void
            map_feature_handlers (FeatureHandlerMap& hmap)
            {
                hmap[LV2_OPTIONS__options] = &I<Derived>::handle_feature;
            }

            /** @internal Handle the options feature */
            static void
            handle_feature (void* instance, FeatureData data)
            {
                Derived* plugin (reinterpret_cast<Derived*> (instance));
                I<Derived>* mixin (static_cast<I<Derived>*> (plugin));
                mixin->p_supplied_opts = (Option*) data;
                mixin->m_ok = true;
            }

            /** @internal Sanity check the mixin */
            bool
            check_ok()
            {
                if (LVTK_DEBUG) {
                    std::clog <<"    [Options] validation "
                              <<(this->m_ok ? "succeeded" : "failed")<<"."<<std::endl;
                }
                return this->m_ok;
            }

            /** @skip */
            static const void*
            extension_data (const char* uri)
            {
               #if LVTK_OPTIONS_IFACE
                if (! strcmp (uri, LV2_OPTIONS__interface)) {
                    static LV2_Options_Interface options = { &I<Derived>::_get,
                                                             &I<Derived>::_set };
                    return &options;
                }
               #endif
                return 0;
            }

            /** Get the options passed by the host as an LV2_Feature

                @note The options array MUST NOT be modified by the plugin instance
                @return The options array or NULL if no options were supplied
             */
            const Option* get_supplied_options()       { return p_supplied_opts; }

        protected:

            /** Get the given options.

                Each element of the passed options array MUST have type, subject, and
                key set.  All other fields (size, type, value) MUST be initialised to
                zero, and are set to the option value if such an option is found.

                This method corresponds with LV2_Options_Interface::get

                @return Bitwise OR of OptionsStatus values.
            */
            uint32_t get_options (Option*)              { return OPTIONS_SUCCESS; }

            /** Set the given options.

                This function is in the "instantiation" LV2 threading class, so no other
                instance functions may be called concurrently.

                This method corresponds with LV2_Options_Interface::set

                @return Bitwise OR of OptionsStatus values.
            */
            uint32_t set_options (const Option*)        { return OPTIONS_SUCCESS; }

        private:

            /** @internal Options supplied by the host.
                This is non-const because it will be set after the ctor is
                called
            */
            Option* p_supplied_opts;

            /* LV2 Options Implementation */

            static uint32_t _get (LV2_Handle handle, LV2_Options_Option* options)
            {
                Derived* plugin (reinterpret_cast<Derived*> (handle));
                return plugin->get_options (options);
            }

            static uint32_t _set (LV2_Handle handle, const LV2_Options_Option* options)
            {
                Derived* plugin (reinterpret_cast<Derived*> (handle));
                return plugin->set_options (options);
            }

        };
    };

} /* namespace lvtk */

#endif /* LVTK_OPTIONS_HPP */
<commit_msg>Changing NULL's to 0's<commit_after>/*
    options.hpp - Support file for writing LV2 plugins in C++

    Copyright (C) 2013 Michael Fisher <mfisher31@gmail.com>

    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.

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307  USA
*/

/** @file options.hpp
    LV2 Compatibility: LV2 Options v1.0 (2012-10-14)
 */

#ifndef LVTK_OPTIONS_HPP
#define LVTK_OPTIONS_HPP

#include <lv2/lv2plug.in/ns/ext/options/options.h>

#ifndef LVTK_OPTIONS_IFACE
#define LVTK_OPTIONS_IFACE 1
#endif

namespace lvtk {

    /** Convenience enum to get LV2_Options_Option into a C++ namespace */
    typedef LV2_Options_Option Option;

    /** Convenience enum to get LV2_Options_Context into a C++ namespace */
    typedef enum {
        /** This option applies to the instance itself.  The subject must be
            ignored. */
        OPTIONS_INSTANCE    = LV2_OPTIONS_INSTANCE,

        /** This option applies to some named resource.  The subject is a URI mapped
            to an integer (a LV2_URID, like the key) */
        OPTIONS_RESOURCE    = LV2_OPTIONS_RESOURCE,

        /** This option applies to some blank node.  The subject is a blank node
            identifier, which is valid only within the current local scope. */
        OPTIONS_BLANK       = LV2_OPTIONS_BLANK,

        /** This option applies to a port on the instance.  The subject is the
            port's index. */
        OPTIONS_PORT        = LV2_OPTIONS_PORT
    } OptionsContext;

    /** Convenience enum to get LV2_Options_Status into a C++ namespace */
    typedef enum {
        OPTIONS_SUCCESS         = LV2_OPTIONS_SUCCESS,          /**< Completed successfully. */
        OPTIONS_ERR_UNKNOWN     = LV2_OPTIONS_ERR_UNKNOWN,      /**< Unknown error. */
        OPTIONS_ERR_BAD_SUBJECT = LV2_OPTIONS_ERR_BAD_SUBJECT,  /**< Invalid/unsupported subject. */
        OPTIONS_ERR_BAD_KEY     = LV2_OPTIONS_ERR_BAD_KEY,      /**< Invalid/unsupported key. */
        OPTIONS_ERR_BAD_VALUE   = LV2_OPTIONS_ERR_BAD_VALUE     /**< Invalid/unsupported value. */
    } OptionsStatus;

    class OptionsIter
    {
    public:

        OptionsIter (const Option* options)
            : index (0),m_size (0), p_opts (options)
        {
            while (0 != next())
                ++m_size;
            index = 0;
        }

        /** */
        const Option* next()
        {
            if (p_opts == 0 || (p_opts[index].key   == 0 &&
                                   p_opts[index].value == 0))
                return 0;

            return &p_opts[index++];
        }

        uint32_t size()     const       { return m_size; }

    private:

        /** @internal The current option index */
        uint32_t           index;

        /** @internal The number of options in the array */
        uint32_t           m_size;

        /** @internal Non constant iteration pointer */
        const Option*      p_opts;

    };

    /** The LV2 Options Feature Mixin

        This mixin provides a callback handler for the LV2 Options feature and
        hooks up the LV2_Options_Interface as extension data.

        @struct lvtk::Options lvtk/ext/options.hpp
        @ingroup pluginmixins
        @ingroup guimixins
     */
    template <bool Required = false>
    struct Options
    {

        template <class Derived>
        struct I : Extension<Required>
        {

            /** @skip */
            I() : p_supplied_opts (0) { }

            /** @skip */
            static void
            map_feature_handlers (FeatureHandlerMap& hmap)
            {
                hmap[LV2_OPTIONS__options] = &I<Derived>::handle_feature;
            }

            /** @internal Handle the options feature */
            static void
            handle_feature (void* instance, FeatureData data)
            {
                Derived* plugin (reinterpret_cast<Derived*> (instance));
                I<Derived>* mixin (static_cast<I<Derived>*> (plugin));
                mixin->p_supplied_opts = (Option*) data;
                mixin->m_ok = true;
            }

            /** @internal Sanity check the mixin */
            bool
            check_ok()
            {
                if (LVTK_DEBUG) {
                    std::clog <<"    [Options] validation "
                              <<(this->m_ok ? "succeeded" : "failed")<<"."<<std::endl;
                }
                return this->m_ok;
            }

            /** @skip */
            static const void*
            extension_data (const char* uri)
            {
               #if LVTK_OPTIONS_IFACE
                if (! strcmp (uri, LV2_OPTIONS__interface)) {
                    static LV2_Options_Interface options = { &I<Derived>::_get,
                                                             &I<Derived>::_set };
                    return &options;
                }
               #endif
                return 0;
            }

            /** Get the options passed by the host as an LV2_Feature

                @note The options array MUST NOT be modified by the plugin instance
                @return The options array or 0 if no options were supplied
             */
            const Option* get_supplied_options()       { return p_supplied_opts; }

        protected:

            /** Get the given options.

                Each element of the passed options array MUST have type, subject, and
                key set.  All other fields (size, type, value) MUST be initialised to
                zero, and are set to the option value if such an option is found.

                This method corresponds with LV2_Options_Interface::get

                @return Bitwise OR of OptionsStatus values.
            */
            uint32_t get_options (Option*)              { return OPTIONS_SUCCESS; }

            /** Set the given options.

                This function is in the "instantiation" LV2 threading class, so no other
                instance functions may be called concurrently.

                This method corresponds with LV2_Options_Interface::set

                @return Bitwise OR of OptionsStatus values.
            */
            uint32_t set_options (const Option*)        { return OPTIONS_SUCCESS; }

        private:

            /** @internal Options supplied by the host.
                This is non-const because it will be set after the ctor is
                called
            */
            Option* p_supplied_opts;

            /* LV2 Options Implementation */

            static uint32_t _get (LV2_Handle handle, LV2_Options_Option* options)
            {
                Derived* plugin (reinterpret_cast<Derived*> (handle));
                return plugin->get_options (options);
            }

            static uint32_t _set (LV2_Handle handle, const LV2_Options_Option* options)
            {
                Derived* plugin (reinterpret_cast<Derived*> (handle));
                return plugin->set_options (options);
            }

        };
    };

} /* namespace lvtk */

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