<commit_before>/* Copyright (C) 2000-2003 MySQL AB

   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-1307  USA */

/*
  UNION  of select's
  UNION's  were introduced by Monty and Sinisa <sinisa@mysql.com>
*/

#include "mysql_priv.h"
#include "sql_select.h"

int mysql_union(THD *thd, LEX *lex, select_result *result,
		SELECT_LEX_UNIT *unit, bool tables_and_fields_initied)
{
  DBUG_ENTER("mysql_union");
  int res= 0;
  if (!(res= unit->prepare(thd, result, tables_and_fields_initied)))
    res= unit->exec();
  res|= unit->cleanup();
  DBUG_RETURN(res);
}

/***************************************************************************
** store records in temporary table for UNION
***************************************************************************/

select_union::select_union(TABLE *table_par)
  :table(table_par), not_describe(0)
{
  bzero((char*) &info,sizeof(info));
  /*
    We can always use DUP_IGNORE because the temporary table will only
    contain a unique key if we are using not using UNION ALL
  */
  info.handle_duplicates= DUP_IGNORE;
}

select_union::~select_union()
{
}

int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
  unit= u;
  if (not_describe && list.elements != table->fields)
  {
    my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
	       ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
    return -1;
  }
  return 0;
}

bool select_union::send_data(List<Item> &values)
{
  if (unit->offset_limit_cnt)
  {						// using limit offset,count
    unit->offset_limit_cnt--;
    return 0;
  }
  fill_record(table->field,values);
  if (thd->net.report_error || write_record(table,&info))
  {
    if (thd->net.last_errno == ER_RECORD_FILE_FULL)
    {
      thd->clear_error(); // do not report user about table overflow
      if (create_myisam_from_heap(thd, table, tmp_table_param,
				  info.last_errno, 0))
	return 1;
    }
    else
      return 1;
  }
  return 0;
}

bool select_union::send_eof()
{
  return 0;
}

bool select_union::flush()
{
  int error;
  if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
  {
    table->file->print_error(error,MYF(0));
    ::send_error(thd);
    return 1;
  }
  return 0;
}

int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
				bool tables_and_fields_initied)
{
  SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
  SELECT_LEX *select_cursor;
  TMP_TABLE_PARAM tmp_table_param;
  DBUG_ENTER("st_select_lex_unit::prepare");

  if (prepared)
    DBUG_RETURN(0);
  prepared= 1;
  res= 0;
  found_rows_for_union= 0;
  TMP_TABLE_PARAM *tmp_table_param= (TMP_TABLE_PARAM *)sql_calloc(sizeof(TMP_TABLE_PARAM));
  result= sel_result;
  t_and_f= tables_and_fields_initied;

  thd->lex.current_select= select_cursor= first_select_in_union();
  /* Global option */
  if (((void*)(global_parameters)) == ((void*)this))
  {
    found_rows_for_union= first_select()->options & OPTION_FOUND_ROWS &&
      global_parameters->select_limit;
    if (found_rows_for_union)
      first_select()->options ^=  OPTION_FOUND_ROWS;
  }
  if (t_and_f)
  {
    // Item list and tables will be initialized by mysql_derived
    item_list= select_cursor->item_list;
  }
  else
  {
    item_list.empty();
    TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first;

    if (setup_tables(first_table) ||
	setup_wild(thd, first_table, select_cursor->item_list, 0,
		   select_cursor->with_wild))
      goto err;
    List_iterator<Item> it(select_cursor->item_list);
    Item *item;
    while((item=it++))
      item->maybe_null=1;
    item_list= select_cursor->item_list;
    select_cursor->with_wild= 0;
    if (setup_ref_array(thd, &select_cursor->ref_pointer_array,
			(item_list.elements + select_cursor->with_sum_func +
			 select_cursor->order_list.elements +
			 select_cursor->group_list.elements)) ||
	setup_fields(thd, select_cursor->ref_pointer_array, first_table,
		     item_list, 0, 0, 1))
      goto err;
    t_and_f= 1;
  }

  tmp_table_param->field_count=item_list.elements;
  if (!(table= create_tmp_table(thd, tmp_table_param, item_list,
				(ORDER*) 0, !union_option,
				1, (select_cursor->options | thd->options |
				    TMP_TABLE_ALL_COLUMNS),
				HA_POS_ERROR)))
    goto err;
  table->file->extra(HA_EXTRA_WRITE_CACHE);
  table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
  bzero((char*) &result_table_list,sizeof(result_table_list));
  result_table_list.db= (char*) "";
  result_table_list.real_name=result_table_list.alias= (char*) "union";
  result_table_list.table=table;

  if (!(union_result=new select_union(table)))
    goto err;

  union_result->not_describe=1;
  union_result->tmp_table_param=tmp_table_param;

  /*
    The following piece of code is placed here solely for the purpose of
    getting correct results with EXPLAIN when UNION is withing a sub-select
    or derived table ...
  */

  if (thd->lex.describe)
  {
    for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
    {
      JOIN *join= new JOIN(thd, sl->item_list,
			   sl->options | thd->options | SELECT_NO_UNLOCK,
			   union_result);
      thd->lex.current_select= sl;
      offset_limit_cnt= sl->offset_limit;
      select_limit_cnt= sl->select_limit+sl->offset_limit;
      if (select_limit_cnt < sl->select_limit)
	select_limit_cnt= HA_POS_ERROR;		// no limit
      if (select_limit_cnt == HA_POS_ERROR)
	sl->options&= ~OPTION_FOUND_ROWS;

      res= join->prepare(&sl->ref_pointer_array,
			 (TABLE_LIST*) sl->table_list.first, sl->with_wild,
			 sl->where,
			 ((sl->braces) ? sl->order_list.elements : 0) +
			 sl->group_list.elements,
			 (sl->braces) ?
			 (ORDER *)sl->order_list.first : (ORDER *) 0,
			 (ORDER*) sl->group_list.first,
			 sl->having,
			 (ORDER*) NULL,
			 sl, this, t_and_f);
      t_and_f= 0;
      if (res || thd->is_fatal_error)
	goto err;
    }
  }

  item_list.empty();
  thd->lex.current_select= lex_select_save;
  {
    List_iterator<Item> it(select_cursor->item_list);
    Field **field;

    for (field= table->field; *field; field++)
    {
      (void) it++;
      if (item_list.push_back(new Item_field(*field)))
	DBUG_RETURN(-1);
    }
  }

  DBUG_RETURN(res || thd->is_fatal_error ? 1 : 0);
err:
  thd->lex.current_select= lex_select_save;
  DBUG_RETURN(-1);
}

int st_select_lex_unit::exec()
{
  int do_print_slow= 0;
  SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
  SELECT_LEX *select_cursor=first_select_in_union(), *last_select;
  DBUG_ENTER("st_select_lex_unit::exec");

  LINT_INIT(last_select);

  if (executed && !(dependent || uncacheable))
    DBUG_RETURN(0);
  executed= 1;

  if ((dependent || uncacheable) || !item || !item->assigned())
  {
    if (optimized && item && item->assigned())
    {
      item->assigned(0); // We will reinit & rexecute unit
      item->reset();
      table->file->delete_all_rows();
    }
    for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
    {
      last_select=sl;
      if (optimized)
	res= sl->join->reinit();
      else
      {
	JOIN *join= new JOIN(thd, sl->item_list,
			     sl->options | thd->options | SELECT_NO_UNLOCK,
			     union_result);
	thd->lex.current_select= sl;
	offset_limit_cnt= sl->offset_limit;
	select_limit_cnt= sl->select_limit+sl->offset_limit;
	if (select_limit_cnt < sl->select_limit)
	  select_limit_cnt= HA_POS_ERROR;		// no limit
	if (select_limit_cnt == HA_POS_ERROR)
	  sl->options&= ~OPTION_FOUND_ROWS;

	res= join->prepare(&sl->ref_pointer_array,
			   (TABLE_LIST*) sl->table_list.first, sl->with_wild,
			   sl->where,
			   ((sl->braces) ? sl->order_list.elements : 0) +
			   sl->group_list.elements,
			   (sl->braces) ?
			   (ORDER *)sl->order_list.first : (ORDER *) 0,
			   (ORDER*) sl->group_list.first,
			   sl->having,
			   (ORDER*) NULL,
			   sl, this, t_and_f);
	t_and_f=0;
	if (res | thd->is_fatal_error)
	{
	  thd->lex.current_select= lex_select_save;
	  DBUG_RETURN(res);
	}
	res= sl->join->optimize();
      }
      if (!res)
      {
	sl->join->exec();
	res= sl->join->error;
	if (!res && union_result->flush())
	{
	  thd->lex.current_select= lex_select_save;
	  DBUG_RETURN(1);
	}
      }
      if (res)
      {
	thd->lex.current_select= lex_select_save;
	DBUG_RETURN(res);
      }
      do_print_slow|= select_cursor->options;
    }
  }
  optimized= 1;

  /* Send result to 'result' */

  // to correct ORDER BY reference resolving
  thd->lex.current_select= select_cursor;
  res= -1;
  {
    List<Item_func_match> empty_list;
    empty_list.empty();

    if (!thd->is_fatal_error)			// Check if EOM
    {
      SELECT_LEX *fake_select  = new SELECT_LEX();
      fake_select->make_empty_select(last_select);
      offset_limit_cnt= (select_cursor->braces ?
			 global_parameters->offset_limit : 0);
      select_limit_cnt= (select_cursor->braces ?
			 global_parameters->select_limit+
			 global_parameters->offset_limit : HA_POS_ERROR);
      if (select_limit_cnt < global_parameters->select_limit)
	select_limit_cnt= HA_POS_ERROR;		// no limit
      if (select_limit_cnt == HA_POS_ERROR)
	thd->options&= ~OPTION_FOUND_ROWS;
      fake_select->ftfunc_list= &empty_list;

      res= mysql_select(thd, &ref_pointer_array, &result_table_list,
			0, item_list, NULL,
			global_parameters->order_list.elements,
			(ORDER*)global_parameters->order_list.first,
			(ORDER*) NULL, NULL, (ORDER*) NULL,
			thd->options, result, this, fake_select, 0);
      if (found_rows_for_union && !res)
	thd->limit_found_rows = (ulonglong)table->file->records;
      fake_select->exclude();
      delete fake_select;
      /*
	Mark for slow query log if any of the union parts didn't use
	indexes efficiently
      */
      select_cursor->options= ((select_cursor->options &
				~(QUERY_NO_INDEX_USED |
				  QUERY_NO_GOOD_INDEX_USED)) |
			       do_print_slow &
			       (QUERY_NO_INDEX_USED |
				QUERY_NO_GOOD_INDEX_USED));
    }
  }
  thd->lex.current_select= lex_select_save;
  DBUG_RETURN(res);
}

int st_select_lex_unit::cleanup()
{
  int error= 0;
  DBUG_ENTER("st_select_lex_unit::cleanup");

  if (union_result)
  {
    delete union_result;
    if (table)
      free_tmp_table(thd, table);
    table= 0; // Safety
  }
  for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
  {
    JOIN *join;
    if ((join= sl->join))
    {
      error|= sl->join->cleanup(thd);
      delete join;
    }
  }
  DBUG_RETURN(error);
}
<commit_msg>Post - post merge fix.<commit_after>/* Copyright (C) 2000-2003 MySQL AB

   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-1307  USA */

/*
  UNION  of select's
  UNION's  were introduced by Monty and Sinisa <sinisa@mysql.com>
*/

#include "mysql_priv.h"
#include "sql_select.h"

int mysql_union(THD *thd, LEX *lex, select_result *result,
		SELECT_LEX_UNIT *unit, bool tables_and_fields_initied)
{
  DBUG_ENTER("mysql_union");
  int res= 0;
  if (!(res= unit->prepare(thd, result, tables_and_fields_initied)))
    res= unit->exec();
  res|= unit->cleanup();
  DBUG_RETURN(res);
}

/***************************************************************************
** store records in temporary table for UNION
***************************************************************************/

select_union::select_union(TABLE *table_par)
  :table(table_par), not_describe(0)
{
  bzero((char*) &info,sizeof(info));
  /*
    We can always use DUP_IGNORE because the temporary table will only
    contain a unique key if we are using not using UNION ALL
  */
  info.handle_duplicates= DUP_IGNORE;
}

select_union::~select_union()
{
}

int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
  unit= u;
  if (not_describe && list.elements != table->fields)
  {
    my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
	       ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
    return -1;
  }
  return 0;
}

bool select_union::send_data(List<Item> &values)
{
  if (unit->offset_limit_cnt)
  {						// using limit offset,count
    unit->offset_limit_cnt--;
    return 0;
  }
  fill_record(table->field,values);
  if (thd->net.report_error || write_record(table,&info))
  {
    if (thd->net.last_errno == ER_RECORD_FILE_FULL)
    {
      thd->clear_error(); // do not report user about table overflow
      if (create_myisam_from_heap(thd, table, tmp_table_param,
				  info.last_errno, 0))
	return 1;
    }
    else
      return 1;
  }
  return 0;
}

bool select_union::send_eof()
{
  return 0;
}

bool select_union::flush()
{
  int error;
  if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
  {
    table->file->print_error(error,MYF(0));
    ::send_error(thd);
    return 1;
  }
  return 0;
}

int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
				bool tables_and_fields_initied)
{
  SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
  SELECT_LEX *select_cursor;
  DBUG_ENTER("st_select_lex_unit::prepare");

  if (prepared)
    DBUG_RETURN(0);
  prepared= 1;
  res= 0;
  found_rows_for_union= 0;
  TMP_TABLE_PARAM *tmp_table_param= (TMP_TABLE_PARAM *)sql_calloc(sizeof(TMP_TABLE_PARAM));
  result= sel_result;
  t_and_f= tables_and_fields_initied;

  thd->lex.current_select= select_cursor= first_select_in_union();
  /* Global option */
  if (((void*)(global_parameters)) == ((void*)this))
  {
    found_rows_for_union= first_select()->options & OPTION_FOUND_ROWS &&
      global_parameters->select_limit;
    if (found_rows_for_union)
      first_select()->options ^=  OPTION_FOUND_ROWS;
  }
  if (t_and_f)
  {
    // Item list and tables will be initialized by mysql_derived
    item_list= select_cursor->item_list;
  }
  else
  {
    item_list.empty();
    TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first;

    if (setup_tables(first_table) ||
	setup_wild(thd, first_table, select_cursor->item_list, 0,
		   select_cursor->with_wild))
      goto err;
    List_iterator<Item> it(select_cursor->item_list);
    Item *item;
    while((item=it++))
      item->maybe_null=1;
    item_list= select_cursor->item_list;
    select_cursor->with_wild= 0;
    if (setup_ref_array(thd, &select_cursor->ref_pointer_array,
			(item_list.elements + select_cursor->with_sum_func +
			 select_cursor->order_list.elements +
			 select_cursor->group_list.elements)) ||
	setup_fields(thd, select_cursor->ref_pointer_array, first_table,
		     item_list, 0, 0, 1))
      goto err;
    t_and_f= 1;
  }

  tmp_table_param->field_count=item_list.elements;
  if (!(table= create_tmp_table(thd, tmp_table_param, item_list,
				(ORDER*) 0, !union_option,
				1, (select_cursor->options | thd->options |
				    TMP_TABLE_ALL_COLUMNS),
				HA_POS_ERROR)))
    goto err;
  table->file->extra(HA_EXTRA_WRITE_CACHE);
  table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
  bzero((char*) &result_table_list,sizeof(result_table_list));
  result_table_list.db= (char*) "";
  result_table_list.real_name=result_table_list.alias= (char*) "union";
  result_table_list.table=table;

  if (!(union_result=new select_union(table)))
    goto err;

  union_result->not_describe=1;
  union_result->tmp_table_param=tmp_table_param;

  /*
    The following piece of code is placed here solely for the purpose of
    getting correct results with EXPLAIN when UNION is withing a sub-select
    or derived table ...
  */

  if (thd->lex.describe)
  {
    for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
    {
      JOIN *join= new JOIN(thd, sl->item_list,
			   sl->options | thd->options | SELECT_NO_UNLOCK,
			   union_result);
      thd->lex.current_select= sl;
      offset_limit_cnt= sl->offset_limit;
      select_limit_cnt= sl->select_limit+sl->offset_limit;
      if (select_limit_cnt < sl->select_limit)
	select_limit_cnt= HA_POS_ERROR;		// no limit
      if (select_limit_cnt == HA_POS_ERROR)
	sl->options&= ~OPTION_FOUND_ROWS;

      res= join->prepare(&sl->ref_pointer_array,
			 (TABLE_LIST*) sl->table_list.first, sl->with_wild,
			 sl->where,
			 ((sl->braces) ? sl->order_list.elements : 0) +
			 sl->group_list.elements,
			 (sl->braces) ?
			 (ORDER *)sl->order_list.first : (ORDER *) 0,
			 (ORDER*) sl->group_list.first,
			 sl->having,
			 (ORDER*) NULL,
			 sl, this, t_and_f);
      t_and_f= 0;
      if (res || thd->is_fatal_error)
	goto err;
    }
  }

  item_list.empty();
  thd->lex.current_select= lex_select_save;
  {
    List_iterator<Item> it(select_cursor->item_list);
    Field **field;

    for (field= table->field; *field; field++)
    {
      (void) it++;
      if (item_list.push_back(new Item_field(*field)))
	DBUG_RETURN(-1);
    }
  }

  DBUG_RETURN(res || thd->is_fatal_error ? 1 : 0);
err:
  thd->lex.current_select= lex_select_save;
  DBUG_RETURN(-1);
}

int st_select_lex_unit::exec()
{
  int do_print_slow= 0;
  SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
  SELECT_LEX *select_cursor=first_select_in_union(), *last_select;
  DBUG_ENTER("st_select_lex_unit::exec");

  LINT_INIT(last_select);

  if (executed && !(dependent || uncacheable))
    DBUG_RETURN(0);
  executed= 1;

  if ((dependent || uncacheable) || !item || !item->assigned())
  {
    if (optimized && item && item->assigned())
    {
      item->assigned(0); // We will reinit & rexecute unit
      item->reset();
      table->file->delete_all_rows();
    }
    for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
    {
      last_select=sl;
      if (optimized)
	res= sl->join->reinit();
      else
      {
	JOIN *join= new JOIN(thd, sl->item_list,
			     sl->options | thd->options | SELECT_NO_UNLOCK,
			     union_result);
	thd->lex.current_select= sl;
	offset_limit_cnt= sl->offset_limit;
	select_limit_cnt= sl->select_limit+sl->offset_limit;
	if (select_limit_cnt < sl->select_limit)
	  select_limit_cnt= HA_POS_ERROR;		// no limit
	if (select_limit_cnt == HA_POS_ERROR)
	  sl->options&= ~OPTION_FOUND_ROWS;

	res= join->prepare(&sl->ref_pointer_array,
			   (TABLE_LIST*) sl->table_list.first, sl->with_wild,
			   sl->where,
			   ((sl->braces) ? sl->order_list.elements : 0) +
			   sl->group_list.elements,
			   (sl->braces) ?
			   (ORDER *)sl->order_list.first : (ORDER *) 0,
			   (ORDER*) sl->group_list.first,
			   sl->having,
			   (ORDER*) NULL,
			   sl, this, t_and_f);
	t_and_f=0;
	if (res | thd->is_fatal_error)
	{
	  thd->lex.current_select= lex_select_save;
	  DBUG_RETURN(res);
	}
	res= sl->join->optimize();
      }
      if (!res)
      {
	sl->join->exec();
	res= sl->join->error;
	if (!res && union_result->flush())
	{
	  thd->lex.current_select= lex_select_save;
	  DBUG_RETURN(1);
	}
      }
      if (res)
      {
	thd->lex.current_select= lex_select_save;
	DBUG_RETURN(res);
      }
      do_print_slow|= select_cursor->options;
    }
  }
  optimized= 1;

  /* Send result to 'result' */

  // to correct ORDER BY reference resolving
  thd->lex.current_select= select_cursor;
  res= -1;
  {
    List<Item_func_match> empty_list;
    empty_list.empty();

    if (!thd->is_fatal_error)			// Check if EOM
    {
      SELECT_LEX *fake_select  = new SELECT_LEX();
      fake_select->make_empty_select(last_select);
      offset_limit_cnt= (select_cursor->braces ?
			 global_parameters->offset_limit : 0);
      select_limit_cnt= (select_cursor->braces ?
			 global_parameters->select_limit+
			 global_parameters->offset_limit : HA_POS_ERROR);
      if (select_limit_cnt < global_parameters->select_limit)
	select_limit_cnt= HA_POS_ERROR;		// no limit
      if (select_limit_cnt == HA_POS_ERROR)
	thd->options&= ~OPTION_FOUND_ROWS;
      fake_select->ftfunc_list= &empty_list;

      res= mysql_select(thd, &ref_pointer_array, &result_table_list,
			0, item_list, NULL,
			global_parameters->order_list.elements,
			(ORDER*)global_parameters->order_list.first,
			(ORDER*) NULL, NULL, (ORDER*) NULL,
			thd->options, result, this, fake_select, 0);
      if (found_rows_for_union && !res)
	thd->limit_found_rows = (ulonglong)table->file->records;
      fake_select->exclude();
      delete fake_select;
      /*
	Mark for slow query log if any of the union parts didn't use
	indexes efficiently
      */
      select_cursor->options= ((select_cursor->options &
				~(QUERY_NO_INDEX_USED |
				  QUERY_NO_GOOD_INDEX_USED)) |
			       do_print_slow &
			       (QUERY_NO_INDEX_USED |
				QUERY_NO_GOOD_INDEX_USED));
    }
  }
  thd->lex.current_select= lex_select_save;
  DBUG_RETURN(res);
}

int st_select_lex_unit::cleanup()
{
  int error= 0;
  DBUG_ENTER("st_select_lex_unit::cleanup");

  if (union_result)
  {
    delete union_result;
    if (table)
      free_tmp_table(thd, table);
    table= 0; // Safety
  }
  for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
  {
    JOIN *join;
    if ((join= sl->join))
    {
      error|= sl->join->cleanup(thd);
      delete join;
    }
  }
  DBUG_RETURN(error);
}
<|endoftext|>


<commit_before>#include "../include/chase.h"
#include "../include/testresult.h"
#include "../include/lanczos.h"

#include <random>
#include <boost/program_options.hpp>

namespace po = boost::program_options;

template<typename T>
void readMatrix( T *H, std::string path_in, std::string spin, int kpoint, int index,
                 std::string suffix, int size, bool legacy )
{
  std::ostringstream problem(std::ostringstream::ate);
  if(legacy)
    problem << path_in << "gmat  1 " << std::setw(2) << index << suffix;
  else
    problem << path_in << "mat_" << spin << "_" << std::setfill('0') << std::setw(2)
            << kpoint << "_" << std::setfill('0') << std::setw(2) << index << suffix;

  std::cout << problem.str() << std::endl;
  std::ifstream input( problem.str().c_str(), std::ios::binary );

  if(input.is_open()) {
    input.read((char *) H, sizeof(T) * size);
  } else {
    throw std::string("error reading file: ") + problem.str();
  }
}

int main(int argc, char* argv[])
{

  int N;
  int nev;
  int nex;
  int deg;
  int bgn;
  int end;

  double tol;
  bool sequence;

  std::string path_in;
  std::string mode;
  std::string opt;
  std::string arch;
  std::string path_eigp;
  std::string path_out;
  std::string path_name;

  int kpoint;
  bool legacy;
  std::string spin;

  po::options_description desc("ChASE Options");
  desc.add_options()
    ("help,h", "show this message")
    ("n", po::value<int>(&N)->required(), "Size of the Input Matrix")
    ("nev", po::value<int>(&nev)->required(), "Wanted Number of Eigenpairs")
    ("nex", po::value<int>(&nex)->default_value(25), "Extra Search Dimensions")
    ("deg", po::value<int>(&deg)->default_value(20), "Initial filtering degree")
    ("bgn", po::value<int>(&bgn)->default_value(2), "Start ell")
    ("end", po::value<int>(&end)->default_value(2), "End ell")
    ("spin", po::value<std::string>(&spin)->default_value("d"), "spin")
    ("kpoint", po::value<int>(&kpoint)->default_value(0), "kpoint")
    ("tol", po::value<double>(&tol)->default_value(1e-10), "Tolerance for Eigenpair convergence")
    ("path_in", po::value<std::string>(&path_in)->required(), "Path to the input matrix/matrices")
    ("mode", po::value<std::string>(&mode)->default_value("A"), "valid values are R(andom) or A(pproximate)")
    ("opt", po::value<std::string>(&opt)->default_value("S"), "Optimi(S)e degree, or do (N)ot optimise")
    ("path_eigp", po::value<std::string>(&path_eigp), "Path to approximate solutions, only required when mode is Approximate, otherwise not used")
    ("sequence", po::value<bool>(&sequence)->default_value(false), "Treat as sequence of Problems. Previous ChASE solution is used, when available")
    ("legacy", po::value<bool>(&legacy)->default_value(false), "Use legacy naming scheme?")
    ;

  std::string testName;
  po::options_description testOP("Test options");
  testOP.add_options()
    ("write", "Write Profile")
    ("name", po::value<std::string>(&testName)->required(), "Name of the testing profile")
    ;

  desc.add(testOP);

  po::variables_map vm;
  po::store(po::parse_command_line(argc, argv, desc), vm);

  if (vm.count("help")) {
    std::cout
      << desc << std::endl;
    return 1;
  }

  try {
    po::notify(vm);
  }
  catch( std::exception &e )
  {
    std::cout
      << e.what() << std::endl
      << std::endl
      << desc << std::endl;
    return -1;
  }

  mode = toupper(mode.at(0));
  opt = toupper(opt.at(0));

  if( bgn > end )
  {
    std::cout << "Begin must be smaller than End!" << std::endl;
    return -1;
  }

  if( mode != "R" && mode != "A" )
  {
    std::cout
      << "Illegal value for mode: \"" << mode << "\"" << std::endl
      << "Legal values are R or A" << std::endl;
    return -1;
  }

  if( opt != "N" && opt != "S" && opt != "M" )
  {
    std::cout
      << "Illegal value for opt: " << opt << std::endl
      << "Legal values are N, S, M" << std::endl;
    return -1;
  }

  if( path_eigp.empty() && mode == "A" )
  {
    std::cout << "eigp is required when mode is " << mode << std::endl;
    // TODO verify that eigp is a valid path
    return -1;
  }

  // -----Validation of test----
  bool testResultWrite;
  if( vm.count("write") )
    testResultWrite = CHASE_TESTRESULT_WRITE;
  else
    testResultWrite = CHASE_TESTRESULT_COMPARE;

  TestResult TR(
    testResultWrite,
    testName,
    N,
    nev,
    nex,
    deg,
    tol,
    mode[0],
    opt[0],
    sequence
    );

  const int nevex = nev + nex; // Block size for the algorithm.

  // Matrix representing the generalized eigenvalue problem.
  MKL_Complex16 *H = new MKL_Complex16[N*N];
  // Matrix which stores the approximate eigenvectors
  MKL_Complex16 *V = new MKL_Complex16[N*nevex];
  // Matrix which stores the eigenvectors
  MKL_Complex16 *W = new MKL_Complex16[N*nevex];
  // eigenvalues
  double * Lambda = new double[nevex];
  int *degrees  = new int[nevex];

  //----------------------------------------------------------------------------
  //std::random_device rd;
  std::mt19937 gen(2342.0);
  std::normal_distribution<> d;

  for (int i = bgn; i <= end ; ++i)
  {
    if( i == bgn || !sequence )
    {
      /*
	if (path_eigp == "_" && int_mode == OMP_APPROX && i == bgn )
	{ // APPROX. No approximate pairs given.
	  //-------------------------SOLVE-PREVIOUS-PROBLEM-------------------------
	  app = ".bin"; // Read the matrix of the previous problem.
	  myreadwrite<MKL_Complex16>(H, path_in.c_str(), app.c_str(), i-1, N*N, 'r');

	  // Solve the previous problem, store the eigenpairs in V and Lambda.
	  ZHEEVR("V", "I", "L", &N, H, &N, &vl, &vu, &il, &iu, &tol,
	  &notneeded, Lambda, V, &N, isuppz, zmem, &lzmem, dmem, &ldmem,
	  imem, &limem, &INFO);

	  //------------------------------------------------------------------------
	  // In next iteration the solutions to this one will be used as approximations.
	  path_eigp = path_out;
	  }
	  else */
      if (mode[0] == CHASE_MODE_APPROX)
      { // APPROX. Approximate eigenpairs given.
        //-----------------------READ-APPROXIMATE-EIGENPAIRS----------------------
        readMatrix( V, path_eigp, spin, kpoint, i-1, ".vct", N*nevex, legacy );
        readMatrix( Lambda, path_eigp, spin, kpoint, i-1, ".vls", nevex, legacy );
        //------------------------------------------------------------------------
      }
      else
      { // RANDOM.
        // Randomize V.
        for( std::size_t i=0; i < N*nevex; ++i)
        {
          V[i] = std::complex<double>( d(gen), d(gen) );
        }
        // Set Lambda to zeros. ( Lambda = zeros(N,1) )
        for(int j=0; j<nevex; j++)
          Lambda[j]=0.0;
      }
    }
    else
    {
      // when doing a sequence and we are not in the first iteration, we use the
      // previous solution
      mode = "A";
    }
    readMatrix( H, path_in, spin, kpoint, i, ".bin", N*N, legacy);

    // test lanczos
    {
      double upperb;
      double *ritzv_;
      MKL_Complex16 *V_;
      int num_its = 10;
      int numvecs = 4;
      if( mode[0] == CHASE_MODE_RANDOM )
      {
        ritzv_ = new double[nevex];
        V_ = new MKL_Complex16[num_its*N];
        num_its = std::min(40,nevex/numvecs);
        num_its = std::max(1,num_its);
      }
      std::cout << "Starting lanczos - main" << std::endl;
      lanczos( H, N, numvecs, num_its, nevex, &upperb,
               mode[0] == CHASE_MODE_RANDOM,
               ritzv_, V_);
      std::cout << "End lanczos - main" << std::endl;
      if( mode[0] == CHASE_MODE_RANDOM )
      {
        double lambda = * std::min_element( ritzv_, ritzv_ + nevex );
        double lowerb = * std::max_element( ritzv_, ritzv_ + nevex );
        TR.registerValue( i, "lambda1", lambda );
        TR.registerValue( i, "lowerb", lowerb );
	std::cout << "Free memory" << std::endl;
        delete[] ritzv_;
        delete[] V_;
      }
      TR.registerValue( i, "upperb", upperb );
    }
    std::cout << "starting chase" << std::endl;
    //------------------------------SOLVE-CURRENT-PROBLEM-----------------------
    chase(H, N, V, W, Lambda, nev, nex, deg, degrees, tol, mode[0], opt[0]);
    //--------------------------------------------------------------------------

    int iterations = get_iter_count();
    int filteredVecs = get_filtered_vecs();

    TR.registerValue( i, "filteredVecs", filteredVecs );
    TR.registerValue( i, "iterations", iterations );

    //-------------------------- Calculate Residuals ---------------------------
    memcpy(W, V, sizeof(MKL_Complex16)*N*nev);
    MKL_Complex16 one(1.0);
    MKL_Complex16 zero(0.0);
    MKL_Complex16 eigval;
    int iOne = 1;
    for(int ttz = 0; ttz<nev;ttz++){
      eigval = -1.0 * Lambda[ttz];
      cblas_zscal( N, &eigval, W+ttz*N, 1);
    }
    cblas_zhemm(
      CblasColMajor,
      CblasLeft,
      CblasLower,
      N, nev, &one, H, N, V, N, &one, W, N);
    double norm = LAPACKE_zlange( LAPACK_COL_MAJOR, 'M', N, nev, W, N);
    TR.registerValue( i, "resd", norm);

    // Check eigenvector orthogonality
    MKL_Complex16 *unity = new MKL_Complex16[nev*nev];
    MKL_Complex16 neg_one(-1.0);
    for(int ttz = 0; ttz < nev; ttz++){
      for(int tty = 0; tty < nev; tty++){
        if(ttz == tty) unity[nev*ttz+tty] = 1.0;
        else unity[nev*ttz+tty] = 0.0;
      }
    }

    cblas_zgemm(
      CblasColMajor,
      CblasConjTrans, CblasNoTrans,
      nev, nev, N,
      &one,
      V, N,
      V, N,
      &neg_one,
      unity, nev
      );
    double norm2 = LAPACKE_zlange( LAPACK_COL_MAJOR, 'M', nev, nev, unity, nev);
    TR.registerValue( i, "orth", norm2);

    delete[] unity;

    std::cout << "resd: " << norm << "\torth:" << norm2 << std::endl;

    print_timings();
    reset_clock();
    std::cout << "Filtered Vectors\t\t" << filteredVecs << std::endl;

    std::cout << "Eigenvalues: " << std::endl;
    for(int zzt = 0; zzt < nev; zzt++)
      std::cout << Lambda[zzt] << std::endl;
    std::cout << "End of eigenvalues. " << std::endl;
  } // for(int i = bgn; i <= end; ++i)

  TR.done();

  delete[] H;
  delete[] V; delete[] W;
  delete[] Lambda;
  //delete[] zmem; delete[] dmem; delete[] imem;
  //delete[] isuppz;

  return 0;
}
<commit_msg>Fixed Bug in Lanczos call in Driver (main.cpp)<commit_after>#include "../include/chase.h"
#include "../include/testresult.h"
#include "../include/lanczos.h"

#include <random>
#include <boost/program_options.hpp>

namespace po = boost::program_options;

template<typename T>
void readMatrix( T *H, std::string path_in, std::string spin, int kpoint, int index,
                 std::string suffix, int size, bool legacy )
{
  std::ostringstream problem(std::ostringstream::ate);
  if(legacy)
    problem << path_in << "gmat  1 " << std::setw(2) << index << suffix;
  else
    problem << path_in << "mat_" << spin << "_" << std::setfill('0') << std::setw(2)
            << kpoint << "_" << std::setfill('0') << std::setw(2) << index << suffix;

  std::cout << problem.str() << std::endl;
  std::ifstream input( problem.str().c_str(), std::ios::binary );

  if(input.is_open()) {
    input.read((char *) H, sizeof(T) * size);
  } else {
    throw std::string("error reading file: ") + problem.str();
  }
}

int main(int argc, char* argv[])
{

  int N;
  int nev;
  int nex;
  int deg;
  int bgn;
  int end;

  double tol;
  bool sequence;

  std::string path_in;
  std::string mode;
  std::string opt;
  std::string arch;
  std::string path_eigp;
  std::string path_out;
  std::string path_name;

  int kpoint;
  bool legacy;
  std::string spin;

  po::options_description desc("ChASE Options");
  desc.add_options()
    ("help,h", "show this message")
    ("n", po::value<int>(&N)->required(), "Size of the Input Matrix")
    ("nev", po::value<int>(&nev)->required(), "Wanted Number of Eigenpairs")
    ("nex", po::value<int>(&nex)->default_value(25), "Extra Search Dimensions")
    ("deg", po::value<int>(&deg)->default_value(20), "Initial filtering degree")
    ("bgn", po::value<int>(&bgn)->default_value(2), "Start ell")
    ("end", po::value<int>(&end)->default_value(2), "End ell")
    ("spin", po::value<std::string>(&spin)->default_value("d"), "spin")
    ("kpoint", po::value<int>(&kpoint)->default_value(0), "kpoint")
    ("tol", po::value<double>(&tol)->default_value(1e-10), "Tolerance for Eigenpair convergence")
    ("path_in", po::value<std::string>(&path_in)->required(), "Path to the input matrix/matrices")
    ("mode", po::value<std::string>(&mode)->default_value("A"), "valid values are R(andom) or A(pproximate)")
    ("opt", po::value<std::string>(&opt)->default_value("S"), "Optimi(S)e degree, or do (N)ot optimise")
    ("path_eigp", po::value<std::string>(&path_eigp), "Path to approximate solutions, only required when mode is Approximate, otherwise not used")
    ("sequence", po::value<bool>(&sequence)->default_value(false), "Treat as sequence of Problems. Previous ChASE solution is used, when available")
    ("legacy", po::value<bool>(&legacy)->default_value(false), "Use legacy naming scheme?")
    ;

  std::string testName;
  po::options_description testOP("Test options");
  testOP.add_options()
    ("write", "Write Profile")
    ("name", po::value<std::string>(&testName)->required(), "Name of the testing profile")
    ;

  desc.add(testOP);

  po::variables_map vm;
  po::store(po::parse_command_line(argc, argv, desc), vm);

  if (vm.count("help")) {
    std::cout
      << desc << std::endl;
    return 1;
  }

  try {
    po::notify(vm);
  }
  catch( std::exception &e )
  {
    std::cout
      << e.what() << std::endl
      << std::endl
      << desc << std::endl;
    return -1;
  }

  mode = toupper(mode.at(0));
  opt = toupper(opt.at(0));

  if( bgn > end )
  {
    std::cout << "Begin must be smaller than End!" << std::endl;
    return -1;
  }

  if( mode != "R" && mode != "A" )
  {
    std::cout
      << "Illegal value for mode: \"" << mode << "\"" << std::endl
      << "Legal values are R or A" << std::endl;
    return -1;
  }

  if( opt != "N" && opt != "S" && opt != "M" )
  {
    std::cout
      << "Illegal value for opt: " << opt << std::endl
      << "Legal values are N, S, M" << std::endl;
    return -1;
  }

  if( path_eigp.empty() && mode == "A" )
  {
    std::cout << "eigp is required when mode is " << mode << std::endl;
    // TODO verify that eigp is a valid path
    return -1;
  }

  // -----Validation of test----
  bool testResultWrite;
  if( vm.count("write") )
    testResultWrite = CHASE_TESTRESULT_WRITE;
  else
    testResultWrite = CHASE_TESTRESULT_COMPARE;

  TestResult TR(
    testResultWrite,
    testName,
    N,
    nev,
    nex,
    deg,
    tol,
    mode[0],
    opt[0],
    sequence
    );

  const int nevex = nev + nex; // Block size for the algorithm.

  // Matrix representing the generalized eigenvalue problem.
  MKL_Complex16 *H = new MKL_Complex16[N*N];
  // Matrix which stores the approximate eigenvectors
  MKL_Complex16 *V = new MKL_Complex16[N*nevex];
  // Matrix which stores the eigenvectors
  MKL_Complex16 *W = new MKL_Complex16[N*nevex];
  // eigenvalues
  double * Lambda = new double[nevex];
  int *degrees  = new int[nevex];

  //----------------------------------------------------------------------------
  //std::random_device rd;
  std::mt19937 gen(2342.0);
  std::normal_distribution<> d;

  for (int i = bgn; i <= end ; ++i)
  {
    if( i == bgn || !sequence )
    {
      /*
	if (path_eigp == "_" && int_mode == OMP_APPROX && i == bgn )
	{ // APPROX. No approximate pairs given.
	  //-------------------------SOLVE-PREVIOUS-PROBLEM-------------------------
	  app = ".bin"; // Read the matrix of the previous problem.
	  myreadwrite<MKL_Complex16>(H, path_in.c_str(), app.c_str(), i-1, N*N, 'r');

	  // Solve the previous problem, store the eigenpairs in V and Lambda.
	  ZHEEVR("V", "I", "L", &N, H, &N, &vl, &vu, &il, &iu, &tol,
	  &notneeded, Lambda, V, &N, isuppz, zmem, &lzmem, dmem, &ldmem,
	  imem, &limem, &INFO);

	  //------------------------------------------------------------------------
	  // In next iteration the solutions to this one will be used as approximations.
	  path_eigp = path_out;
	  }
	  else */
      if (mode[0] == CHASE_MODE_APPROX)
      { // APPROX. Approximate eigenpairs given.
        //-----------------------READ-APPROXIMATE-EIGENPAIRS----------------------
        readMatrix( V, path_eigp, spin, kpoint, i-1, ".vct", N*nevex, legacy );
        readMatrix( Lambda, path_eigp, spin, kpoint, i-1, ".vls", nevex, legacy );
        //------------------------------------------------------------------------
      }
      else
      { // RANDOM.
        // Randomize V.
        for( std::size_t i=0; i < N*nevex; ++i)
        {
          V[i] = std::complex<double>( d(gen), d(gen) );
        }
        // Set Lambda to zeros. ( Lambda = zeros(N,1) )
        for(int j=0; j<nevex; j++)
          Lambda[j]=0.0;
      }
    }
    else
    {
      // when doing a sequence and we are not in the first iteration, we use the
      // previous solution
      mode = "A";
    }
    readMatrix( H, path_in, spin, kpoint, i, ".bin", N*N, legacy);

    // test lanczos
    {
      double upperb;
      double *ritzv_;
      MKL_Complex16 *V_;
      int num_its = 10;
      int numvecs = 4;
      if( mode[0] == CHASE_MODE_RANDOM )
      {
        ritzv_ = new double[nevex];
        num_its = std::min(40,nevex/numvecs);
        num_its = std::max(1,num_its);
        V_ = new MKL_Complex16[num_its*N];
      }
      std::cout << "Starting lanczos - main" << std::endl;
      lanczos( H, N, numvecs, num_its, nevex, &upperb,
               mode[0] == CHASE_MODE_RANDOM,
               ritzv_, V_);
      std::cout << "End lanczos - main" << std::endl;
      if( mode[0] == CHASE_MODE_RANDOM )
      {
        double lambda = * std::min_element( ritzv_, ritzv_ + nevex );
        double lowerb = * std::max_element( ritzv_, ritzv_ + nevex );
        TR.registerValue( i, "lambda1", lambda );
        TR.registerValue( i, "lowerb", lowerb );
	std::cout << "Free memory" << std::endl;
        delete[] ritzv_;
        delete[] V_;
      }
      TR.registerValue( i, "upperb", upperb );
    }
    std::cout << "starting chase" << std::endl;
    //------------------------------SOLVE-CURRENT-PROBLEM-----------------------
    chase(H, N, V, W, Lambda, nev, nex, deg, degrees, tol, mode[0], opt[0]);
    //--------------------------------------------------------------------------

    int iterations = get_iter_count();
    int filteredVecs = get_filtered_vecs();

    TR.registerValue( i, "filteredVecs", filteredVecs );
    TR.registerValue( i, "iterations", iterations );

    //-------------------------- Calculate Residuals ---------------------------
    memcpy(W, V, sizeof(MKL_Complex16)*N*nev);
    MKL_Complex16 one(1.0);
    MKL_Complex16 zero(0.0);
    MKL_Complex16 eigval;
    int iOne = 1;
    for(int ttz = 0; ttz<nev;ttz++){
      eigval = -1.0 * Lambda[ttz];
      cblas_zscal( N, &eigval, W+ttz*N, 1);
    }
    cblas_zhemm(
      CblasColMajor,
      CblasLeft,
      CblasLower,
      N, nev, &one, H, N, V, N, &one, W, N);
    double norm = LAPACKE_zlange( LAPACK_COL_MAJOR, 'M', N, nev, W, N);
    TR.registerValue( i, "resd", norm);

    // Check eigenvector orthogonality
    MKL_Complex16 *unity = new MKL_Complex16[nev*nev];
    MKL_Complex16 neg_one(-1.0);
    for(int ttz = 0; ttz < nev; ttz++){
      for(int tty = 0; tty < nev; tty++){
        if(ttz == tty) unity[nev*ttz+tty] = 1.0;
        else unity[nev*ttz+tty] = 0.0;
      }
    }

    cblas_zgemm(
      CblasColMajor,
      CblasConjTrans, CblasNoTrans,
      nev, nev, N,
      &one,
      V, N,
      V, N,
      &neg_one,
      unity, nev
      );
    double norm2 = LAPACKE_zlange( LAPACK_COL_MAJOR, 'M', nev, nev, unity, nev);
    TR.registerValue( i, "orth", norm2);

    delete[] unity;

    std::cout << "resd: " << norm << "\torth:" << norm2 << std::endl;

    print_timings();
    reset_clock();
    std::cout << "Filtered Vectors\t\t" << filteredVecs << std::endl;

    std::cout << "Eigenvalues: " << std::endl;
    for(int zzt = 0; zzt < nev; zzt++)
      std::cout << Lambda[zzt] << std::endl;
    std::cout << "End of eigenvalues. " << std::endl;
  } // for(int i = bgn; i <= end; ++i)

  TR.done();

  delete[] H;
  delete[] V; delete[] W;
  delete[] Lambda;
  //delete[] zmem; delete[] dmem; delete[] imem;
  //delete[] isuppz;

  return 0;
}
<|endoftext|>


<commit_before>#include "XInputFetcher.h"
#include <math.h>

int XInputFetcher::s_btnMaskMap[InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS] =
{
	XINPUT_GAMEPAD_DPAD_UP,
	XINPUT_GAMEPAD_DPAD_DOWN,
	XINPUT_GAMEPAD_DPAD_LEFT,
	XINPUT_GAMEPAD_DPAD_RIGHT,
	XINPUT_GAMEPAD_START,
	XINPUT_GAMEPAD_BACK,
	XINPUT_GAMEPAD_LEFT_THUMB,
	XINPUT_GAMEPAD_RIGHT_THUMB,
	XINPUT_GAMEPAD_LEFT_SHOULDER,
	XINPUT_GAMEPAD_RIGHT_SHOULDER,
	XINPUT_GAMEPAD_A,
	XINPUT_GAMEPAD_B,
	XINPUT_GAMEPAD_X,
	XINPUT_GAMEPAD_Y
};

XInputFetcher::XInputFetcher()
{
	m_epsilon = 0.0;

	ZeroMemory( &m_analogOffsets, sizeof(m_analogOffsets) );
	ZeroMemory( &m_currentState, sizeof(XINPUT_STATE) );
}

XInputFetcher::~XInputFetcher()
{
}

void XInputFetcher::update()
{
	//XINPUT_STATE newState;
	ZeroMemory( &m_currentState, sizeof(XINPUT_STATE) );
	unsigned long result = XInputGetState( 0, &m_currentState );
	if( result == ERROR_SUCCESS )
	{
		for( int i=0; i<InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS; i++)
		{
			bool pressed = m_currentState.Gamepad.wButtons & s_btnMaskMap[i];
			m_btns[i] = InputHelper::calcState( m_btns[i], pressed );
		}
	}
	//m_currentState = newState;

	m_rawAnalogs[InputHelper::THUMB_LX_POSITIVE] = m_currentState.Gamepad.sThumbLX;
	m_rawAnalogs[InputHelper::THUMB_LY_POSITIVE] = m_currentState.Gamepad.sThumbLY;
	m_rawAnalogs[InputHelper::THUMB_RX_POSITIVE] = m_currentState.Gamepad.sThumbRX;
	m_rawAnalogs[InputHelper::THUMB_RY_POSITIVE] = m_currentState.Gamepad.sThumbRY;
	m_rawAnalogs[InputHelper::THUMB_LX_NEGATIVE] = m_currentState.Gamepad.sThumbLX;
	m_rawAnalogs[InputHelper::THUMB_LY_NEGATIVE] = m_currentState.Gamepad.sThumbLY;
	m_rawAnalogs[InputHelper::THUMB_RX_NEGATIVE] = m_currentState.Gamepad.sThumbRX;
	m_rawAnalogs[InputHelper::THUMB_RY_NEGATIVE] = m_currentState.Gamepad.sThumbRY;
	m_rawAnalogs[InputHelper::TRIGGER_L] = (short)m_currentState.Gamepad.bLeftTrigger;
	m_rawAnalogs[InputHelper::TRIGGER_R] = (short)m_currentState.Gamepad.bRightTrigger;
}

InputHelper::KEY_STATE XInputFetcher::getBtnState( int p_btn )
{
	if( 0 <= p_btn && p_btn < InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS )
		return m_btns[p_btn];
	else
		return InputHelper::KEY_STATE::NON_EXISTING_STATE;
}

short XInputFetcher::getRawAnalog( int p_analog )
{
	if( 0 <= p_analog && p_analog < InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS )
		return m_rawAnalogs[p_analog];
	else
		return -1;
}

double XInputFetcher::getCalibratedAnalog( int p_analog )
{
	// Std-val. Whats returned if the analog isn't found.
	double val = (float)-1;

	// Make sure that p_analog is in range
	if( 0 <= p_analog && p_analog < InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS )
	{
		// Offset the input by the offset calculated by calibrate()
		short tmp = getRawAnalog( p_analog ) - m_analogOffsets[p_analog] ;

		// Triggers have a precision of 0-255 instead of 0-65k as the thumb sticks.
		// Take that into account when calculating 0.0 - 1.0
		if(p_analog == InputHelper::TRIGGER_L || p_analog == InputHelper::TRIGGER_R)
			val =  (double)tmp / 255; //BYTE_MAX
		else
			val = (double)tmp / SHRT_MAX;

		// Dead zone adjustment
		if( abs(val) < m_epsilon )
			val = 0.0;
	}

	return val;
}

void XInputFetcher::calibrate( double p_epsilon )
{
	m_epsilon = p_epsilon;

	// Calibrate _bad_ (those that are reeeeeally bad) gamepads
	update();

	for( int i=0; i<InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS; i++)
	{
		m_analogOffsets[i] = getRawAnalog(i);
	}
}
<commit_msg>Fixed gamepad calibration bug.<commit_after>#include "XInputFetcher.h"
#include <math.h>

int XInputFetcher::s_btnMaskMap[InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS] =
{
	XINPUT_GAMEPAD_DPAD_UP,
	XINPUT_GAMEPAD_DPAD_DOWN,
	XINPUT_GAMEPAD_DPAD_LEFT,
	XINPUT_GAMEPAD_DPAD_RIGHT,
	XINPUT_GAMEPAD_START,
	XINPUT_GAMEPAD_BACK,
	XINPUT_GAMEPAD_LEFT_THUMB,
	XINPUT_GAMEPAD_RIGHT_THUMB,
	XINPUT_GAMEPAD_LEFT_SHOULDER,
	XINPUT_GAMEPAD_RIGHT_SHOULDER,
	XINPUT_GAMEPAD_A,
	XINPUT_GAMEPAD_B,
	XINPUT_GAMEPAD_X,
	XINPUT_GAMEPAD_Y
};

XInputFetcher::XInputFetcher()
{
	m_epsilon = 0.0;

	ZeroMemory( &m_analogOffsets, sizeof(m_analogOffsets) );
	ZeroMemory( &m_currentState, sizeof(XINPUT_STATE) );
}

XInputFetcher::~XInputFetcher()
{
}

void XInputFetcher::update()
{
	//XINPUT_STATE newState;
	ZeroMemory( &m_currentState, sizeof(XINPUT_STATE) );
	unsigned long result = XInputGetState( 0, &m_currentState );
	if( result == ERROR_SUCCESS )
	{
		for( int i=0; i<InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS; i++)
		{
			bool pressed = m_currentState.Gamepad.wButtons & s_btnMaskMap[i];
			m_btns[i] = InputHelper::calcState( m_btns[i], pressed );
		}
	}
	//m_currentState = newState;

	m_rawAnalogs[InputHelper::THUMB_LX_POSITIVE] = m_currentState.Gamepad.sThumbLX;
	m_rawAnalogs[InputHelper::THUMB_LY_POSITIVE] = m_currentState.Gamepad.sThumbLY;
	m_rawAnalogs[InputHelper::THUMB_RX_POSITIVE] = m_currentState.Gamepad.sThumbRX;
	m_rawAnalogs[InputHelper::THUMB_RY_POSITIVE] = m_currentState.Gamepad.sThumbRY;
	m_rawAnalogs[InputHelper::THUMB_LX_NEGATIVE] = m_currentState.Gamepad.sThumbLX;
	m_rawAnalogs[InputHelper::THUMB_LY_NEGATIVE] = m_currentState.Gamepad.sThumbLY;
	m_rawAnalogs[InputHelper::THUMB_RX_NEGATIVE] = m_currentState.Gamepad.sThumbRX;
	m_rawAnalogs[InputHelper::THUMB_RY_NEGATIVE] = m_currentState.Gamepad.sThumbRY;
	m_rawAnalogs[InputHelper::TRIGGER_L] = (short)m_currentState.Gamepad.bLeftTrigger;
	m_rawAnalogs[InputHelper::TRIGGER_R] = (short)m_currentState.Gamepad.bRightTrigger;
}

InputHelper::KEY_STATE XInputFetcher::getBtnState( int p_btn )
{
	if( 0 <= p_btn && p_btn < InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS )
		return m_btns[p_btn];
	else
		return InputHelper::KEY_STATE::NON_EXISTING_STATE;
}

short XInputFetcher::getRawAnalog( int p_analog )
{
	if( 0 <= p_analog && p_analog < InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS )
		return m_rawAnalogs[p_analog];
	else
		return -1;
}

double XInputFetcher::getCalibratedAnalog( int p_analog )
{
	// Std-val. Whats returned if the analog isn't found.
	double val = (float)-1;

	// Make sure that p_analog is in range
	if( 0 <= p_analog && p_analog < InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS )
	{
		// Offset the input by the offset calculated by calibrate()
		int calibratedInput = getRawAnalog( p_analog ) - m_analogOffsets[p_analog] ;
		short clampedInput = calibratedInput;

		if( calibratedInput > SHRT_MAX ) {
			clampedInput = SHRT_MAX;
		} else if( calibratedInput < SHRT_MIN ) {
			clampedInput = SHRT_MIN;
		}

		// Triggers have a precision of 0-255 instead of 0-65k as the thumb sticks.
		// Take that into account when calculating 0.0 - 1.0
		if(p_analog == InputHelper::TRIGGER_L || p_analog == InputHelper::TRIGGER_R)
			val =  (double)clampedInput / 255; //BYTE_MAX
		else
			val = (double)clampedInput / SHRT_MAX;

		// Dead zone adjustment
		if( abs(val) < m_epsilon )
			val = 0.0;

	}

	return val;
}

void XInputFetcher::calibrate( double p_epsilon )
{
	m_epsilon = p_epsilon;

	// Calibrate _bad_ (those that are reeeeeally bad) gamepads
	update();

	for( int i=0; i<InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS; i++)
	{
		m_analogOffsets[i] = getRawAnalog(i);
	}
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkWindowToImageFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "vtkWindowToImageFilter.h"
#include "vtkRenderWindow.h"
#include "vtkObjectFactory.h"

vtkCxxRevisionMacro(vtkWindowToImageFilter, "1.9");
vtkStandardNewMacro(vtkWindowToImageFilter);

//----------------------------------------------------------------------------
vtkWindowToImageFilter::vtkWindowToImageFilter()
{
  this->Input = NULL;
  this->Magnification = 1;
}

//----------------------------------------------------------------------------
vtkWindowToImageFilter::~vtkWindowToImageFilter()
{
  if (this->Input)
    {
    this->Input->UnRegister(this);
    this->Input = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkWindowToImageFilter::SetInput(vtkWindow *input)
{
  if (input != this->Input)
    {
    if (this->Input) {this->Input->UnRegister(this);}
    this->Input = input;
    if (this->Input) {this->Input->Register(this);}
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkWindowToImageFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageSource::PrintSelf(os,indent);

  if ( this->Input )
    {
    os << indent << "Input:\n";
    this->Input->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Input: (none)\n";
    }
  os << indent << "Magnification: " << this->Magnification << "\n";
}

//----------------------------------------------------------------------------
// This method returns the largest region that can be generated.
void vtkWindowToImageFilter::ExecuteInformation()
{
  if (this->Input == NULL )
    {
    vtkErrorMacro(<<"Please specify a renderer as input!");
    return;
    }
  vtkImageData *out = this->GetOutput();

  // set the extent
  out->SetWholeExtent(0,
                      this->Input->GetSize()[0]*this->Magnification - 1,
                      0,
                      this->Input->GetSize()[1]*this->Magnification - 1,
                      0, 0);

  // set the spacing
  out->SetSpacing(1.0, 1.0, 1.0);

  // set the origin.
  out->SetOrigin(0.0, 0.0, 0.0);

  // set the scalar components
  out->SetNumberOfScalarComponents(3);
  out->SetScalarType(VTK_UNSIGNED_CHAR);
}

//----------------------------------------------------------------------------
// This function reads a region from a file.  The regions extent/axes
// are assumed to be the same as the file extent/order.
void vtkWindowToImageFilter::ExecuteData(vtkDataObject *vtkNotUsed(data))
{
  vtkImageData *out = this->GetOutput();
  out->SetExtent(out->GetWholeExtent());
  out->AllocateScalars();

  int outIncrY;
  int size[2];
  unsigned char *pixels, *outPtr;
  int idxY, rowSize;
  int i;

  if (out->GetScalarType() != VTK_UNSIGNED_CHAR)
    {
    vtkErrorMacro("mismatch in scalar types!");
    return;
    }

  // get the size of the render window
  size[0] = this->Input->GetSize()[0];
  size[1] = this->Input->GetSize()[1];
  rowSize = size[0]*3;
  outIncrY = size[0]*this->Magnification*3;

  float *viewAngles;
  double *windowCenters;
  vtkRenderWindow *renWin = vtkRenderWindow::SafeDownCast(this->Input);
  if (!renWin)
    {
    vtkWarningMacro("The window passed to window to image should be a RenderWIndow or one of its subclasses");
    return;
    }

  vtkRendererCollection *rc = renWin->GetRenderers();
  vtkRenderer *aren;
  vtkCamera *cam;
  int numRenderers = rc->GetNumberOfItems();

  // for each renderer
  vtkCamera **cams = new vtkCamera *[numRenderers];
  viewAngles = new float [numRenderers];
  windowCenters = new double [numRenderers*2];
  double *parallelScale = new double [numRenderers];
  rc->InitTraversal();
  for (i = 0; i < numRenderers; ++i)
    {
    aren = rc->GetNextItem();
    cams[i] = aren->GetActiveCamera();
    cams[i]->Register(this);
    cams[i]->GetWindowCenter(windowCenters+i*2);
    viewAngles[i] = cams[i]->GetViewAngle();
    parallelScale[i] = cams[i]->GetParallelScale();
    cam = vtkCamera::New();
    cam->SetPosition(cams[i]->GetPosition());
    cam->SetFocalPoint(cams[i]->GetFocalPoint());
    cam->SetViewUp(cams[i]->GetViewUp());
    cam->SetClippingRange(cams[i]->GetClippingRange());
    cam->SetParallelProjection(cams[i]->GetParallelProjection());
    aren->SetActiveCamera(cam);
    }

  // render each of the tiles required to fill this request
  this->Input->SetTileScale(this->Magnification);
  this->Input->GetSize();

  int x, y;
  for (y = 0; y < this->Magnification; y++)
    {
    for (x = 0; x < this->Magnification; x++)
      {
      // setup the Window ivars
      this->Input->SetTileViewport((float)x/this->Magnification,
                                   (float)y/this->Magnification,
                                   (x+1.0)/this->Magnification,
                                   (y+1.0)/this->Magnification);
      float *tvp = this->Input->GetTileViewport();

      // for each renderer, setup camera
      rc->InitTraversal();
      for (i = 0; i < numRenderers; ++i)
        {
        aren = rc->GetNextItem();
        cam = aren->GetActiveCamera();
        float *vp = aren->GetViewport();
        float visVP[4];
        visVP[0] = (vp[0] >= tvp[0]) ? vp[0] : tvp[0];
        visVP[1] = (vp[1] >= tvp[1]) ? vp[1] : tvp[1];
        visVP[2] = (vp[2] <= tvp[2]) ? vp[2] : tvp[2];
        visVP[3] = (vp[3] <= tvp[3]) ? vp[3] : tvp[3];
        // compute magnification
        float mag = (visVP[3] - visVP[1])/(vp[3] - vp[1]);
        // compute the delta
        float deltax = (visVP[2] + visVP[0])/2.0 - (vp[2] + vp[0])/2.0;
        float deltay = (visVP[3] + visVP[1])/2.0 - (vp[3] + vp[1])/2.0;
        // scale by original window size
        if (visVP[2] - visVP[0] > 0)
          {
          deltax = 2.0*deltax/(visVP[2] - visVP[0]);
          }
        if (visVP[3] - visVP[1] > 0)
          {
          deltay = 2.0*deltay/(visVP[3] - visVP[1]);
          }
        cam->SetWindowCenter(deltax,deltay);
        cam->SetViewAngle(asin(sin(viewAngles[i]*3.1415926/360.0)*mag)
                          * 360.0 / 3.1415926);
        cam->SetParallelScale(parallelScale[i]*mag);
        }

      // now render the tile and get the data
      this->Input->Render();
      pixels = this->Input->GetPixelData(0,0,size[0] - 1,
                                         size[1] - 1, 1);
      unsigned char *pixels1 = pixels;

      // now write the data to the output image
      outPtr =
        (unsigned char *)out->GetScalarPointer(x*size[0],y*size[1], 0);

      // Loop through ouput pixels
      for (idxY = 0; idxY < size[1]; idxY++)
        {
        memcpy(outPtr,pixels1,rowSize);
        outPtr += outIncrY;
        pixels1 += rowSize;
        }

      // free the memory
      delete [] pixels;
      }
    }

  // restore settings
  // for each renderer
  rc->InitTraversal();
  for (i = 0; i < numRenderers; ++i)
    {
    aren = rc->GetNextItem();
    // store the old view angle & set the new
    cam = aren->GetActiveCamera();
    aren->SetActiveCamera(cams[i]);
    cams[i]->UnRegister(this);
    cam->Delete();
    }
  delete [] viewAngles;
  delete [] windowCenters;
  delete [] parallelScale;
  delete [] cams;

  // render each of the tiles required to fill this request
  this->Input->SetTileScale(1);
  this->Input->SetTileViewport(0.0,0.0,1.0,1.0);
  this->Input->GetSize();
}

<commit_msg>fixed missing cam property<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkWindowToImageFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "vtkWindowToImageFilter.h"
#include "vtkRenderWindow.h"
#include "vtkObjectFactory.h"

vtkCxxRevisionMacro(vtkWindowToImageFilter, "1.10");
vtkStandardNewMacro(vtkWindowToImageFilter);

//----------------------------------------------------------------------------
vtkWindowToImageFilter::vtkWindowToImageFilter()
{
  this->Input = NULL;
  this->Magnification = 1;
}

//----------------------------------------------------------------------------
vtkWindowToImageFilter::~vtkWindowToImageFilter()
{
  if (this->Input)
    {
    this->Input->UnRegister(this);
    this->Input = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkWindowToImageFilter::SetInput(vtkWindow *input)
{
  if (input != this->Input)
    {
    if (this->Input) {this->Input->UnRegister(this);}
    this->Input = input;
    if (this->Input) {this->Input->Register(this);}
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkWindowToImageFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageSource::PrintSelf(os,indent);

  if ( this->Input )
    {
    os << indent << "Input:\n";
    this->Input->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Input: (none)\n";
    }
  os << indent << "Magnification: " << this->Magnification << "\n";
}

//----------------------------------------------------------------------------
// This method returns the largest region that can be generated.
void vtkWindowToImageFilter::ExecuteInformation()
{
  if (this->Input == NULL )
    {
    vtkErrorMacro(<<"Please specify a renderer as input!");
    return;
    }
  vtkImageData *out = this->GetOutput();

  // set the extent
  out->SetWholeExtent(0,
                      this->Input->GetSize()[0]*this->Magnification - 1,
                      0,
                      this->Input->GetSize()[1]*this->Magnification - 1,
                      0, 0);

  // set the spacing
  out->SetSpacing(1.0, 1.0, 1.0);

  // set the origin.
  out->SetOrigin(0.0, 0.0, 0.0);

  // set the scalar components
  out->SetNumberOfScalarComponents(3);
  out->SetScalarType(VTK_UNSIGNED_CHAR);
}

//----------------------------------------------------------------------------
// This function reads a region from a file.  The regions extent/axes
// are assumed to be the same as the file extent/order.
void vtkWindowToImageFilter::ExecuteData(vtkDataObject *vtkNotUsed(data))
{
  vtkImageData *out = this->GetOutput();
  out->SetExtent(out->GetWholeExtent());
  out->AllocateScalars();

  int outIncrY;
  int size[2];
  unsigned char *pixels, *outPtr;
  int idxY, rowSize;
  int i;

  if (out->GetScalarType() != VTK_UNSIGNED_CHAR)
    {
    vtkErrorMacro("mismatch in scalar types!");
    return;
    }

  // get the size of the render window
  size[0] = this->Input->GetSize()[0];
  size[1] = this->Input->GetSize()[1];
  rowSize = size[0]*3;
  outIncrY = size[0]*this->Magnification*3;

  float *viewAngles;
  double *windowCenters;
  vtkRenderWindow *renWin = vtkRenderWindow::SafeDownCast(this->Input);
  if (!renWin)
    {
    vtkWarningMacro("The window passed to window to image should be a RenderWIndow or one of its subclasses");
    return;
    }

  vtkRendererCollection *rc = renWin->GetRenderers();
  vtkRenderer *aren;
  vtkCamera *cam;
  int numRenderers = rc->GetNumberOfItems();

  // for each renderer
  vtkCamera **cams = new vtkCamera *[numRenderers];
  viewAngles = new float [numRenderers];
  windowCenters = new double [numRenderers*2];
  double *parallelScale = new double [numRenderers];
  rc->InitTraversal();
  for (i = 0; i < numRenderers; ++i)
    {
    aren = rc->GetNextItem();
    cams[i] = aren->GetActiveCamera();
    cams[i]->Register(this);
    cams[i]->GetWindowCenter(windowCenters+i*2);
    viewAngles[i] = cams[i]->GetViewAngle();
    parallelScale[i] = cams[i]->GetParallelScale();
    cam = vtkCamera::New();
    cam->SetPosition(cams[i]->GetPosition());
    cam->SetFocalPoint(cams[i]->GetFocalPoint());
    cam->SetViewUp(cams[i]->GetViewUp());
    cam->SetClippingRange(cams[i]->GetClippingRange());
    cam->SetParallelProjection(cams[i]->GetParallelProjection());
    cam->SetFocalDisk(cams[i]->GetFocalDisk());
    aren->SetActiveCamera(cam);
    }

  // render each of the tiles required to fill this request
  this->Input->SetTileScale(this->Magnification);
  this->Input->GetSize();

  int x, y;
  for (y = 0; y < this->Magnification; y++)
    {
    for (x = 0; x < this->Magnification; x++)
      {
      // setup the Window ivars
      this->Input->SetTileViewport((float)x/this->Magnification,
                                   (float)y/this->Magnification,
                                   (x+1.0)/this->Magnification,
                                   (y+1.0)/this->Magnification);
      float *tvp = this->Input->GetTileViewport();

      // for each renderer, setup camera
      rc->InitTraversal();
      for (i = 0; i < numRenderers; ++i)
        {
        aren = rc->GetNextItem();
        cam = aren->GetActiveCamera();
        float *vp = aren->GetViewport();
        float visVP[4];
        visVP[0] = (vp[0] >= tvp[0]) ? vp[0] : tvp[0];
        visVP[1] = (vp[1] >= tvp[1]) ? vp[1] : tvp[1];
        visVP[2] = (vp[2] <= tvp[2]) ? vp[2] : tvp[2];
        visVP[3] = (vp[3] <= tvp[3]) ? vp[3] : tvp[3];
        // compute magnification
        float mag = (visVP[3] - visVP[1])/(vp[3] - vp[1]);
        // compute the delta
        float deltax = (visVP[2] + visVP[0])/2.0 - (vp[2] + vp[0])/2.0;
        float deltay = (visVP[3] + visVP[1])/2.0 - (vp[3] + vp[1])/2.0;
        // scale by original window size
        if (visVP[2] - visVP[0] > 0)
          {
          deltax = 2.0*deltax/(visVP[2] - visVP[0]);
          }
        if (visVP[3] - visVP[1] > 0)
          {
          deltay = 2.0*deltay/(visVP[3] - visVP[1]);
          }
        cam->SetWindowCenter(deltax,deltay);
        cam->SetViewAngle(asin(sin(viewAngles[i]*3.1415926/360.0)*mag)
                          * 360.0 / 3.1415926);
        cam->SetParallelScale(parallelScale[i]*mag);
        }

      // now render the tile and get the data
      this->Input->Render();
      pixels = this->Input->GetPixelData(0,0,size[0] - 1,
                                         size[1] - 1, 1);
      unsigned char *pixels1 = pixels;

      // now write the data to the output image
      outPtr =
        (unsigned char *)out->GetScalarPointer(x*size[0],y*size[1], 0);

      // Loop through ouput pixels
      for (idxY = 0; idxY < size[1]; idxY++)
        {
        memcpy(outPtr,pixels1,rowSize);
        outPtr += outIncrY;
        pixels1 += rowSize;
        }

      // free the memory
      delete [] pixels;
      }
    }

  // restore settings
  // for each renderer
  rc->InitTraversal();
  for (i = 0; i < numRenderers; ++i)
    {
    aren = rc->GetNextItem();
    // store the old view angle & set the new
    cam = aren->GetActiveCamera();
    aren->SetActiveCamera(cams[i]);
    cams[i]->UnRegister(this);
    cam->Delete();
    }
  delete [] viewAngles;
  delete [] windowCenters;
  delete [] parallelScale;
  delete [] cams;

  // render each of the tiles required to fill this request
  this->Input->SetTileScale(1);
  this->Input->SetTileViewport(0.0,0.0,1.0,1.0);
  this->Input->GetSize();
}

<|endoftext|>


<commit_before>/*
 *  Copyright 2010-2011 Fabric Technologies Inc. All rights reserved.
 */

#include <Fabric/EDK/EDK.h>

#include <math.h>

using namespace Fabric::EDK;
IMPLEMENT_FABRIC_EDK_ENTRIES

class Buffer
{
public:

  Buffer( void const *data, size_t size )
    : m_data( static_cast<uint8_t const *>( data ) )
    , m_size( size )
    , m_pos( 0 )
  {
  }

  inline bool read( unsigned char c[], int n )
  {
    if ( m_pos + n <= m_size )
    {
      memcpy( c, &m_data[m_pos], n );
      m_pos += n;
      return true;
    }
    else return false;
  }

  inline bool readline( std::string &str )
  {
    if( m_pos == m_size )
      return false;

    size_t  m_start = m_pos;
    while( m_pos < m_size && m_data[m_pos] != '\n' )
      m_pos++;

    str = std::string( (char const *)m_data, m_start, (m_pos - m_start) );

    if( m_pos < m_size )
      m_pos++;

    return true;
  }

private:
  uint8_t const *m_data;
  size_t m_size;
  size_t m_pos;
};

static bool readHeader(
  Buffer &hdr,
  KL::Size &imageWidth,
  KL::Size &imageHeight
  )
{
  std::string    str;

  if( !hdr.readline( str ) )
    return false;

  if( str[0] != '#' || str[1] != '?' )
    return false;

  bool foundFormat;
  for( ; ; )
  {
    if( !hdr.readline( str ) )
      return false;

    // Empty line signifies end of header
    if( str.empty() )
      break;

    if( str == "FORMAT=32-bit_rle_rgbe" )
      foundFormat = true;
  }
  if( !hdr.readline( str ) )
    return false;

  // Orientation + dimension specified.
  // We currently only accept '-Y M +X n'
  int   w, h;
  if( sscanf( str.c_str(), "-Y %d +X %d", &h, &w ) != 2 )
    return false;

  imageWidth = (KL::Size)w;
  imageHeight = (KL::Size)h;

  return true;
}

static void rgbeToColor( unsigned char rgbe[4], KL::Color &col )
{
  if( rgbe[3] ) {
    float f = ldexp(1.0,rgbe[3]-(int)(128+8));
    col.r = rgbe[0] * f;
    col.g = rgbe[1] * f;
    col.b = rgbe[2] * f;
    col.a = 1.0;
  } else {
    col.r = col.g = col.b = 0.0;
    col.a = 1.0;
  }
}

static bool readPixelsRaw(
  Buffer  &hdr,
  KL::VariableArray<KL::Color> &img,
  size_t  idx,
  size_t  nbPixels
  )
{
  unsigned char rgbe[4];

  while(nbPixels-- > 0) {
    if( !hdr.read( rgbe, 4 ) )
      return false;

    rgbeToColor( rgbe, img[idx] );
    idx++;
  }
  return true;
}

static bool readPixelsRLE(
  Buffer &hdr,
  KL::VariableArray<KL::Color> &img,
  size_t scanlineWidth,
  size_t nbScanlines
  )
{
  if( scanlineWidth < 8 || scanlineWidth > 0x7FFF )
    return readPixelsRaw( hdr, img, 0, scanlineWidth * nbScanlines );

  std::vector<unsigned char>  scanline;
  scanline.resize( scanlineWidth * 4 );

  size_t    idx = 0;

  while( nbScanlines > 0 )
  {
    unsigned char rgbe[4];
    if( !hdr.read( rgbe, 4 ) )
      return false;
    if( rgbe[0] != 2 || rgbe[1] != 2 || rgbe[2] != 0x80 )
    {
      // Not an RLE file
      rgbeToColor( rgbe, img[idx] );
      return readPixelsRaw( hdr, img, idx + 1, scanlineWidth * nbScanlines - 1 );
    }

    if( ( (size_t(rgbe[2]) << 8 ) | size_t(rgbe[3])) != scanlineWidth )
      return false;

    unsigned char *scanlineStart, *scanlineEnd;

    scanlineStart = &scanline[ 0 ];
    for( int i = 0; i < 4; i++ )
    {
      scanlineEnd = &scanline[ (i+1) * scanlineWidth ];
      while( scanlineStart < scanlineEnd )
      {
        unsigned char rle[2];

        if( !hdr.read( rle, 2 ) )
          return false;

        if( rle[0] > 128 )
        {
          // Run of identical values
          size_t count = rle[0] - 128;
          if( count == 0 || count > ( size_t(scanlineEnd) - size_t(scanlineStart) ) )
            return false;
          while( count-- > 0 )
            *scanlineStart++ = rle[1];
        } else {
          // Run of non-identical values
          size_t count = rle[0];
          if( count == 0 || count > ( size_t(scanlineEnd) - size_t(scanlineStart) ) )
            return false;

          *scanlineStart++ = rle[1];
          if( -count > 0 )
          {
            if( !hdr.read( scanlineStart, count ) )
              return false;
            scanlineStart += count;
          }
        }
      }
    }

    for( size_t i = 0; i < scanlineWidth; i++ )
    {
      for( size_t j = 0; j < 4; j++ )
        rgbe[j] = scanline[i + scanlineWidth * j ];

      rgbeToColor( rgbe, img[ idx++ ] );
    }

    nbScanlines--;
  }
  return true;
}

FABRIC_EXT_EXPORT void FabricHDRDecode(
  KL::Data hdrData,
  KL::Size hdrDataSize,
  KL::Size &imageWidth,
  KL::Size &imageHeight,
  KL::VariableArray<KL::Color> &imagePixels
  )
{
  Buffer buffer( hdrData, hdrDataSize );

  if( !readHeader( buffer, imageWidth, imageHeight ) )
    return;

  imagePixels.resize( imageWidth * imageHeight );

  readPixelsRLE( buffer, imagePixels, imageWidth, imageHeight );
}

FABRIC_EXT_EXPORT void FabricHDROpenFileHandle(
  KL::String handle,
  KL::Size &imageWidth,
  KL::Size &imageHeight,
  KL::VariableArray<KL::Color> &imagePixels
  )
{
  KL::FileHandleWrapper wrapper(handle);
  FILE * fp= fopen(wrapper.getPath().data(),"rb");
  if(!fp)
  {
    Fabric::EDK::throwException("PNG Extension: File does not exist!");
    return;
  }

  fseek(fp, 0L, SEEK_END);
  KL::Size size = ftell(fp);
  fseek(fp, 0L, SEEK_SET);

  KL::Data data = malloc(size);
  if(fread(data,1,size,fp) != size)
  {
    fclose(fp);
    Fabric::EDK::throwException("PNG Extension: Could not read file contents!");
    return;
  }
  fclose(fp);

  FabricHDRDecode(data,size,imageWidth,imageHeight,imagePixels);
  free(data);
}
<commit_msg>HDR Extension: Support FileHandle<commit_after>/*
 *  Copyright 2010-2011 Fabric Technologies Inc. All rights reserved.
 */

#include <Fabric/EDK/EDK.h>

#include <math.h>

using namespace Fabric::EDK;
IMPLEMENT_FABRIC_EDK_ENTRIES

class Buffer
{
public:

  Buffer( void const *data, size_t size )
    : m_data( static_cast<uint8_t const *>( data ) )
    , m_size( size )
    , m_pos( 0 )
  {
  }

  inline bool read( unsigned char c[], int n )
  {
    if ( m_pos + n <= m_size )
    {
      memcpy( c, &m_data[m_pos], n );
      m_pos += n;
      return true;
    }
    else return false;
  }

  inline bool readline( std::string &str )
  {
    if( m_pos == m_size )
      return false;

    size_t  m_start = m_pos;
    while( m_pos < m_size && m_data[m_pos] != '\n' )
      m_pos++;

    str = std::string( (char const *)m_data, m_start, (m_pos - m_start) );

    if( m_pos < m_size )
      m_pos++;

    return true;
  }

private:
  uint8_t const *m_data;
  size_t m_size;
  size_t m_pos;
};

static bool readHeader(
  Buffer &hdr,
  KL::Size &imageWidth,
  KL::Size &imageHeight
  )
{
  std::string    str;

  if( !hdr.readline( str ) )
    return false;

  if( str[0] != '#' || str[1] != '?' )
    return false;

  bool foundFormat;
  for( ; ; )
  {
    if( !hdr.readline( str ) )
      return false;

    // Empty line signifies end of header
    if( str.empty() )
      break;

    if( str == "FORMAT=32-bit_rle_rgbe" )
      foundFormat = true;
  }
  if( !hdr.readline( str ) )
    return false;

  // Orientation + dimension specified.
  // We currently only accept '-Y M +X n'
  int   w, h;
  if( sscanf( str.c_str(), "-Y %d +X %d", &h, &w ) != 2 )
    return false;

  imageWidth = (KL::Size)w;
  imageHeight = (KL::Size)h;

  return true;
}

static void rgbeToColor( unsigned char rgbe[4], KL::Color &col )
{
  if( rgbe[3] ) {
    float f = ldexp(1.0,rgbe[3]-(int)(128+8));
    col.r = rgbe[0] * f;
    col.g = rgbe[1] * f;
    col.b = rgbe[2] * f;
    col.a = 1.0;
  } else {
    col.r = col.g = col.b = 0.0;
    col.a = 1.0;
  }
}

static bool readPixelsRaw(
  Buffer  &hdr,
  KL::VariableArray<KL::Color> &img,
  size_t  idx,
  size_t  nbPixels
  )
{
  unsigned char rgbe[4];

  while(nbPixels-- > 0) {
    if( !hdr.read( rgbe, 4 ) )
      return false;

    rgbeToColor( rgbe, img[idx] );
    idx++;
  }
  return true;
}

static bool readPixelsRLE(
  Buffer &hdr,
  KL::VariableArray<KL::Color> &img,
  size_t scanlineWidth,
  size_t nbScanlines
  )
{
  if( scanlineWidth < 8 || scanlineWidth > 0x7FFF )
    return readPixelsRaw( hdr, img, 0, scanlineWidth * nbScanlines );

  std::vector<unsigned char>  scanline;
  scanline.resize( scanlineWidth * 4 );

  size_t    idx = 0;

  while( nbScanlines > 0 )
  {
    unsigned char rgbe[4];
    if( !hdr.read( rgbe, 4 ) )
      return false;
    if( rgbe[0] != 2 || rgbe[1] != 2 || rgbe[2] != 0x80 )
    {
      // Not an RLE file
      rgbeToColor( rgbe, img[idx] );
      return readPixelsRaw( hdr, img, idx + 1, scanlineWidth * nbScanlines - 1 );
    }

    if( ( (size_t(rgbe[2]) << 8 ) | size_t(rgbe[3])) != scanlineWidth )
      return false;

    unsigned char *scanlineStart, *scanlineEnd;

    scanlineStart = &scanline[ 0 ];
    for( int i = 0; i < 4; i++ )
    {
      scanlineEnd = &scanline[ (i+1) * scanlineWidth ];
      while( scanlineStart < scanlineEnd )
      {
        unsigned char rle[2];

        if( !hdr.read( rle, 2 ) )
          return false;

        if( rle[0] > 128 )
        {
          // Run of identical values
          size_t count = rle[0] - 128;
          if( count == 0 || count > ( size_t(scanlineEnd) - size_t(scanlineStart) ) )
            return false;
          while( count-- > 0 )
            *scanlineStart++ = rle[1];
        } else {
          // Run of non-identical values
          size_t count = rle[0];
          if( count == 0 || count > ( size_t(scanlineEnd) - size_t(scanlineStart) ) )
            return false;

          *scanlineStart++ = rle[1];
          if( -count > 0 )
          {
            if( !hdr.read( scanlineStart, count ) )
              return false;
            scanlineStart += count;
          }
        }
      }
    }

    for( size_t i = 0; i < scanlineWidth; i++ )
    {
      for( size_t j = 0; j < 4; j++ )
        rgbe[j] = scanline[i + scanlineWidth * j ];

      rgbeToColor( rgbe, img[ idx++ ] );
    }

    nbScanlines--;
  }
  return true;
}

FABRIC_EXT_EXPORT void FabricHDRDecode(
  KL::Data hdrData,
  KL::Size hdrDataSize,
  KL::Size &imageWidth,
  KL::Size &imageHeight,
  KL::VariableArray<KL::Color> &imagePixels
  )
{
  Buffer buffer( hdrData, hdrDataSize );

  if( !readHeader( buffer, imageWidth, imageHeight ) )
    return;

  imagePixels.resize( imageWidth * imageHeight );

  readPixelsRLE( buffer, imagePixels, imageWidth, imageHeight );
}

FABRIC_EXT_EXPORT void FabricHDROpenFileHandle(
  KL::String handle,
  KL::Size &imageWidth,
  KL::Size &imageHeight,
  KL::VariableArray<KL::Color> &imagePixels
  )
{
  KL::FileHandleWrapper wrapper(handle);
  FILE * fp= fopen(wrapper.getPath().data(),"rb");
  if(!fp)
  {
    Fabric::EDK::throwException("HDR Extension: File does not exist!");
    return;
  }

  fseek(fp, 0L, SEEK_END);
  KL::Size size = ftell(fp);
  fseek(fp, 0L, SEEK_SET);

  KL::Data data = malloc(size);
  if(fread(data,1,size,fp) != size)
  {
    fclose(fp);
    Fabric::EDK::throwException("HDR Extension: Could not read file contents!");
    return;
  }
  fclose(fp);

  FabricHDRDecode(data,size,imageWidth,imageHeight,imagePixels);
  free(data);
}
<|endoftext|>