<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2014 Paul T. Bauman, Roy H. Stogner
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

#include "grins_config.h"

#include <iostream>

// GRINS
#include "grins/mesh_builder.h"
#include "grins/simulation.h"
#include "grins/simulation_builder.h"
#include "grins/multiphysics_sys.h"
#include "grins/parabolic_profile.h"

//libMesh
#include "libmesh/dirichlet_boundaries.h"
#include "libmesh/dof_map.h"
#include "libmesh/fe_base.h"
#include "libmesh/fe_interface.h"
#include "libmesh/mesh_function.h"
#include "libmesh/linear_implicit_system.h"
#include "libmesh/gmv_io.h"
#include "libmesh/exact_solution.h"

// GRVY
#ifdef GRINS_HAVE_GRVY
#include "grvy.h"
#endif

class TurbulentBCFactory : public GRINS::BoundaryConditionsFactory
{
public:

  TurbulentBCFactory(libMesh::MeshFunction* _turbulent_bc_values)
    : GRINS::BoundaryConditionsFactory(),
      turbulent_bc_values(_turbulent_bc_values)
  { return; };

  ~TurbulentBCFactory(){return;};

  std::multimap< GRINS::PhysicsName, GRINS::DBCContainer > build_dirichlet( );

  private:
  // A pointer to a TurbulentBdyFunction object that build_dirichlet can use to set bcs
  libMesh::MeshFunction* turbulent_bc_values;
};

// Class to construct the Dirichlet boundary object and operator for the inlet u velocity and nu profiles
class TurbulentBdyFunction : public libMesh::FunctionBase<libMesh::Number>
{
public:
  TurbulentBdyFunction (libMesh::MeshFunction* _turbulent_bc_values) :
    turbulent_bc_values(_turbulent_bc_values)
  { this->_initialized = true; }

  virtual libMesh::Number operator() (const libMesh::Point&, const libMesh::Real = 0)
  { libmesh_not_implemented(); }

  virtual void operator() (const libMesh::Point& p,
                           const libMesh::Real t,
                           libMesh::DenseVector<libMesh::Number>& output)
  {
    output.resize(4);
    output.zero();
    // Since the turbulent_bc_values object has a solution from a 1-d problem, we have to zero out the y coordinate of p
    libMesh::Point p_copy(p);
    // Also the 1-d solution provided is on the domain [0, 1] on the x axis and we need to map this to the corresponding point on the y axis
    p_copy(0) = p_copy(1);
    p_copy(1)= 0.0;
    if(p_copy(0) > 0.5)
      {
	p_copy(0) = 1 - p_copy(0);
      }
    libMesh::DenseVector<libMesh::Number> u_nu_values;
    turbulent_bc_values->operator()(p_copy, t, u_nu_values);
    output(0) = u_nu_values(0);
    std::cout<<"Velocity bc at ("<<p_copy(1)<<","<<p_copy(0)<<"): "<<u_nu_values(0)<<std::endl;
    output(3) = u_nu_values(1);
    std::cout<<"Viscosity bc at ("<<p_copy(1)<<","<<p_copy(0)<<"): "<<u_nu_values(1)<<std::endl;
  }

  virtual libMesh::AutoPtr<libMesh::FunctionBase<libMesh::Number> > clone() const
  { return libMesh::AutoPtr<libMesh::FunctionBase<libMesh::Number> > (new TurbulentBdyFunction(turbulent_bc_values)); }

private:
  libMesh::MeshFunction* turbulent_bc_values;
};

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

#ifdef GRINS_USE_GRVY_TIMERS
  GRVY::GRVY_Timer_Class grvy_timer;
  grvy_timer.Init("GRINS Timer");
#endif

  // Check command line count.
  if( argc < 2 )
    {
      // TODO: Need more consistent error handling.
      std::cerr << "Error: Must specify libMesh input file." << std::endl;
      exit(1); // TODO: something more sophisticated for parallel runs?
    }

  // libMesh input file should be first argument
  std::string libMesh_input_filename = argv[1];

  // Create our GetPot object.
  GetPot libMesh_inputfile( libMesh_input_filename );

#ifdef GRINS_USE_GRVY_TIMERS
  grvy_timer.BeginTimer("Initialize Solver");
#endif

  // Initialize libMesh library.
  libMesh::LibMeshInit libmesh_init(argc, argv);

  // Build a 1-d turbulent_bc_system to get the bc data from files
  libMesh::SerialMesh mesh(libmesh_init.comm());

  mesh.read("test_data/turbulent_channel_Re944_grid.xda");

  //mesh.all_second_order();

  // And an EquationSystems to run on it
  libMesh::EquationSystems equation_systems (mesh);

  equation_systems.read("test_data/turbulent_channel_soln.xda", libMesh::XdrMODE::READ,
			libMesh::EquationSystems::READ_HEADER |
  			     libMesh::EquationSystems::READ_DATA |
  			     libMesh::EquationSystems::READ_ADDITIONAL_DATA);

  // Get a reference to the system so that we can call update() on it
  libMesh::System & turbulent_bc_system = equation_systems.get_system<libMesh::System>("flow");

  // We need to call update to put system in a consistent state
  // with the solution that was read in
  turbulent_bc_system.update();

  // Write out this solution to make sure it was read properly
  std::ostringstream file_name_gmv;
  file_name_gmv << "turbulent_bc.gmv";

  libMesh::GMVIO(mesh).write_equation_systems
    (file_name_gmv.str(), equation_systems);

  // Print information about the system to the screen.
  equation_systems.print_info();

  // Prepare a global solution and a MeshFunction of the Turbulent system
  libMesh::AutoPtr<libMesh::MeshFunction> turbulent_bc_values;

  libMesh::AutoPtr<libMesh::NumericVector<libMesh::Number> > turbulent_bc_soln = libMesh::NumericVector<libMesh::Number>::build(equation_systems.comm());

  std::vector<unsigned int>turbulent_bc_system_variables;
  turbulent_bc_system_variables.push_back(0);
  turbulent_bc_system_variables.push_back(1);

  std::vector<libMesh::Number> flow_soln;

  turbulent_bc_system.update_global_solution(flow_soln);

  std::cout<<"Flow solution size: "<<flow_soln.size()<<std::endl;

  turbulent_bc_soln->init(libMesh::cast_int<libMesh::numeric_index_type>(flow_soln.size()), true, libMesh::SERIAL);

  turbulent_bc_values = libMesh::AutoPtr<libMesh::MeshFunction>
    (new libMesh::MeshFunction(equation_systems,
			       *turbulent_bc_soln,
			       turbulent_bc_system.get_dof_map(),
			       turbulent_bc_system_variables ));

  turbulent_bc_values->init();

  libMesh::Point p_test(0.3, 0.0);

  libMesh::Real t;

  libMesh::DenseVector<libMesh::Number> u_nu_values;

  turbulent_bc_values->operator()(p_test, t, u_nu_values);

  std::cout<<"Viscosity bc at ("<<p_test(1)<<","<<p_test(0)<<"): "<<u_nu_values(1)<<std::endl;
  std::cout<<"Velocity bc at ("<<p_test(1)<<","<<p_test(0)<<"): "<<u_nu_values(0)<<std::endl;

  GRINS::SimulationBuilder sim_builder;

  std::tr1::shared_ptr<TurbulentBCFactory> bc_factory( new TurbulentBCFactory(turbulent_bc_values.get()) );

  sim_builder.attach_bc_factory(bc_factory);

  GRINS::Simulation grins( libMesh_inputfile,
			   sim_builder,
                           libmesh_init.comm() );

#ifdef GRINS_USE_GRVY_TIMERS
  grvy_timer.EndTimer("Initialize Solver");

  // Attach GRVY timer to solver
  grins.attach_grvy_timer( &grvy_timer );
#endif

  // Solve
  grins.run();

  // Get equation systems to create ExactSolution object
  //std::tr1::shared_ptr<libMesh::EquationSystems> es = grins.get_equation_system();

  // Create Exact solution object and attach exact solution quantities
  //libMesh::ExactSolution exact_sol(*es);

  //exact_sol.attach_exact_value(&exact_solution);
  //exact_sol.attach_exact_deriv(&exact_derivative);

  // Compute error and get it in various norms
  //exact_sol.compute_error("GRINS", "u");

  //double l2error = exact_sol.l2_error("GRINS", "u");
  //double h1error = exact_sol.h1_error("GRINS", "u");

  // Needs to change to 1 based on comparison
  int return_flag = 0;

  // if( l2error > 1.0e-9 || h1error > 1.0e-9 )
  //   {
  //     return_flag = 1;

  //     std::cout << "Tolerance exceeded for velocity in Poiseuille test." << std::endl
  // 		<< "l2 error = " << l2error << std::endl
  // 		<< "h1 error = " << h1error << std::endl;
  //   }

  // // Compute error and get it in various norms
  // exact_sol.compute_error("GRINS", "p");

  // l2error = exact_sol.l2_error("GRINS", "p");
  // h1error = exact_sol.h1_error("GRINS", "p");

  // if( l2error > 2.0e-9 || h1error > 2.0e-9 )
  //   {
  //     return_flag = 1;

  //     std::cout << "Tolerance exceeded for pressure in Poiseuille test." << std::endl
  // 		<< "l2 error = " << l2error << std::endl
  // 		<< "h1 error = " << h1error << std::endl;
  //   }

  return return_flag;
}

std::multimap< GRINS::PhysicsName, GRINS::DBCContainer > TurbulentBCFactory::build_dirichlet( )
{
  std::tr1::shared_ptr<libMesh::FunctionBase<libMesh::Number> > turbulent_inlet( new TurbulentBdyFunction(this->turbulent_bc_values) );

  GRINS::DBCContainer cont_u;
  cont_u.add_var_name( "u" );
  cont_u.add_bc_id( 3 );

  cont_u.set_func( turbulent_inlet );

  GRINS::DBCContainer cont_nu;
  cont_nu.add_var_name( "nu" );
  cont_nu.add_bc_id( 3 );

  cont_nu.set_func( turbulent_inlet );

  std::multimap< GRINS::PhysicsName, GRINS::DBCContainer > mymap;

  mymap.insert( std::pair<GRINS::PhysicsName, GRINS::DBCContainer >(GRINS::incompressible_navier_stokes,  cont_u) );

  mymap.insert( std::pair<GRINS::PhysicsName, GRINS::DBCContainer >(GRINS::spalart_allmaras,  cont_nu) );

  return mymap;
}

// libMesh::Number
// exact_solution( const libMesh::Point& p,
// 		const libMesh::Parameters&,   // parameters, not needed
// 		const std::string&,  // sys_name, not needed
// 		const std::string&); // unk_name, not needed);

// libMesh::Gradient
// exact_derivative( const libMesh::Point& p,
// 		  const libMesh::Parameters&,   // parameters, not needed
// 		  const std::string&,  // sys_name, not needed
// 		  const std::string&); // unk_name, not needed);

// libMesh::Number
// exact_solution( const libMesh::Point& p,
// 		const libMesh::Parameters& /*params*/,   // parameters, not needed
// 		const std::string& /*sys_name*/,  // sys_name, not needed
// 		const std::string& var )  // unk_name, not needed);
// {
//   const double x = p(0);
//   const double y = p(1);

//   libMesh::Number f = 0;
//   // Hardcoded to velocity in input file.
//   if( var == "u" ) f = 4*y*(1-y);
//   else if( var == "p" ) f = 120.0 + (80.0-120.0)/5.0*x;
//   else libmesh_assert(false);

//   return f;
// }

// libMesh::Gradient
// exact_derivative( const libMesh::Point& p,
// 		  const libMesh::Parameters& /*params*/,   // parameters, not needed
// 		  const std::string& /*sys_name*/,  // sys_name, not needed
// 		  const std::string& var)  // unk_name, not needed);
// {
//   const double y = p(1);

//   libMesh::Gradient g;

//   // Hardcoded to velocity in input file.
//   if( var == "u" )
//     {
//       g(0) = 0.0;
//       g(1) = 4*(1-y) - 4*y;

// #if LIBMESH_DIM > 2
//       g(2) = 0.0;
// #endif
//     }

//   if( var == "p" )
//     {
//       g(0) = (80.0-120.0)/5.0;
//       g(1) = 0.0;

// #if LIBMESH_DIM > 2
//       g(2) = 0.0;
// #endif
//     }
//   return g;
// }

<commit_msg>Finally got the MeshFunction to work. The problem was that I was not setting the turbulent_bc_soln equal to flow_soln.<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2014 Paul T. Bauman, Roy H. Stogner
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

#include "grins_config.h"

#include <iostream>

// GRINS
#include "grins/mesh_builder.h"
#include "grins/simulation.h"
#include "grins/simulation_builder.h"
#include "grins/multiphysics_sys.h"
#include "grins/parabolic_profile.h"

//libMesh
#include "libmesh/dirichlet_boundaries.h"
#include "libmesh/dof_map.h"
#include "libmesh/fe_base.h"
#include "libmesh/fe_interface.h"
#include "libmesh/mesh_function.h"
#include "libmesh/linear_implicit_system.h"
#include "libmesh/gmv_io.h"
#include "libmesh/exact_solution.h"

// GRVY
#ifdef GRINS_HAVE_GRVY
#include "grvy.h"
#endif

class TurbulentBCFactory : public GRINS::BoundaryConditionsFactory
{
public:

  TurbulentBCFactory(libMesh::MeshFunction* _turbulent_bc_values)
    : GRINS::BoundaryConditionsFactory(),
      turbulent_bc_values(_turbulent_bc_values)
  { return; };

  ~TurbulentBCFactory(){return;};

  std::multimap< GRINS::PhysicsName, GRINS::DBCContainer > build_dirichlet( );

  private:
  // A pointer to a TurbulentBdyFunction object that build_dirichlet can use to set bcs
  libMesh::MeshFunction* turbulent_bc_values;
};

// Class to construct the Dirichlet boundary object and operator for the inlet u velocity and nu profiles
class TurbulentBdyFunction : public libMesh::FunctionBase<libMesh::Number>
{
public:
  TurbulentBdyFunction (libMesh::MeshFunction* _turbulent_bc_values) :
    turbulent_bc_values(_turbulent_bc_values)
  { this->_initialized = true; }

  virtual libMesh::Number operator() (const libMesh::Point&, const libMesh::Real = 0)
  { libmesh_not_implemented(); }

  virtual void operator() (const libMesh::Point& p,
                           const libMesh::Real t,
                           libMesh::DenseVector<libMesh::Number>& output)
  {
    output.resize(4);
    output.zero();
    // Since the turbulent_bc_values object has a solution from a 1-d problem, we have to zero out the y coordinate of p
    libMesh::Point p_copy(p);
    // Also the 1-d solution provided is on the domain [0, 1] on the x axis and we need to map this to the corresponding point on the y axis
    p_copy(0) = p_copy(1);
    p_copy(1)= 0.0;
    if(p_copy(0) > 0.5)
      {
	p_copy(0) = 1 - p_copy(0);
      }
    libMesh::DenseVector<libMesh::Number> u_nu_values;
    turbulent_bc_values->operator()(p_copy, t, u_nu_values);
    output(0) = u_nu_values(0);
    //std::cout<<"Velocity bc at ("<<p_copy(1)<<","<<p_copy(0)<<"): "<<u_nu_values(0)<<std::endl;
    output(3) = u_nu_values(1);
    //std::cout<<"Viscosity bc at ("<<p_copy(1)<<","<<p_copy(0)<<"): "<<u_nu_values(1)<<std::endl;
  }

  virtual libMesh::AutoPtr<libMesh::FunctionBase<libMesh::Number> > clone() const
  { return libMesh::AutoPtr<libMesh::FunctionBase<libMesh::Number> > (new TurbulentBdyFunction(turbulent_bc_values)); }

private:
  libMesh::MeshFunction* turbulent_bc_values;
};

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

#ifdef GRINS_USE_GRVY_TIMERS
  GRVY::GRVY_Timer_Class grvy_timer;
  grvy_timer.Init("GRINS Timer");
#endif

  // Check command line count.
  if( argc < 2 )
    {
      // TODO: Need more consistent error handling.
      std::cerr << "Error: Must specify libMesh input file." << std::endl;
      exit(1); // TODO: something more sophisticated for parallel runs?
    }

  // libMesh input file should be first argument
  std::string libMesh_input_filename = argv[1];

  // Create our GetPot object.
  GetPot libMesh_inputfile( libMesh_input_filename );

#ifdef GRINS_USE_GRVY_TIMERS
  grvy_timer.BeginTimer("Initialize Solver");
#endif

  // Initialize libMesh library.
  libMesh::LibMeshInit libmesh_init(argc, argv);

  // Build a 1-d turbulent_bc_system to get the bc data from files
  libMesh::SerialMesh mesh(libmesh_init.comm());

  mesh.read("test_data/turbulent_channel_Re944_grid.xda");

  //mesh.all_second_order();

  // And an EquationSystems to run on it
  libMesh::EquationSystems equation_systems (mesh);

  equation_systems.read("test_data/turbulent_channel_soln.xda", libMesh::XdrMODE::READ,
			libMesh::EquationSystems::READ_HEADER |
  			     libMesh::EquationSystems::READ_DATA |
  			     libMesh::EquationSystems::READ_ADDITIONAL_DATA);

  // Get a reference to the system so that we can call update() on it
  libMesh::System & turbulent_bc_system = equation_systems.get_system<libMesh::System>("flow");

  // We need to call update to put system in a consistent state
  // with the solution that was read in
  turbulent_bc_system.update();

  // Write out this solution to make sure it was read properly
  std::ostringstream file_name_gmv;
  file_name_gmv << "turbulent_bc.gmv";

  libMesh::GMVIO(mesh).write_equation_systems
    (file_name_gmv.str(), equation_systems);

  // Print information about the system to the screen.
  equation_systems.print_info();

  // Prepare a global solution and a MeshFunction of the Turbulent system
  libMesh::AutoPtr<libMesh::MeshFunction> turbulent_bc_values;

  libMesh::AutoPtr<libMesh::NumericVector<libMesh::Number> > turbulent_bc_soln = libMesh::NumericVector<libMesh::Number>::build(equation_systems.comm());

  std::vector<unsigned int>turbulent_bc_system_variables;
  turbulent_bc_system_variables.push_back(0);
  turbulent_bc_system_variables.push_back(1);

  std::vector<libMesh::Number> flow_soln;

  turbulent_bc_system.update_global_solution(flow_soln);

  std::cout<<"Flow solution size: "<<flow_soln.size()<<std::endl;

  turbulent_bc_soln->init(libMesh::cast_int<libMesh::numeric_index_type>(flow_soln.size()), true, libMesh::SERIAL);

  (*turbulent_bc_soln) = flow_soln;

  turbulent_bc_values = libMesh::AutoPtr<libMesh::MeshFunction>
    (new libMesh::MeshFunction(equation_systems,
			       *turbulent_bc_soln,
			       turbulent_bc_system.get_dof_map(),
			       turbulent_bc_system_variables ));

  turbulent_bc_values->init();

  // libMesh::Point p_test(0.3, 0.0);

  // libMesh::Real t;

  // libMesh::DenseVector<libMesh::Number> u_nu_values;

  // turbulent_bc_values->operator()(p_test, t, u_nu_values);

  // std::cout<<"Viscosity bc at ("<<p_test(1)<<","<<p_test(0)<<"): "<<u_nu_values(1)<<std::endl;
  // std::cout<<"Velocity bc at ("<<p_test(1)<<","<<p_test(0)<<"): "<<u_nu_values(0)<<std::endl;

  GRINS::SimulationBuilder sim_builder;

  std::tr1::shared_ptr<TurbulentBCFactory> bc_factory( new TurbulentBCFactory(turbulent_bc_values.get()) );

  sim_builder.attach_bc_factory(bc_factory);

  GRINS::Simulation grins( libMesh_inputfile,
			   sim_builder,
                           libmesh_init.comm() );

#ifdef GRINS_USE_GRVY_TIMERS
  grvy_timer.EndTimer("Initialize Solver");

  // Attach GRVY timer to solver
  grins.attach_grvy_timer( &grvy_timer );
#endif

  // Solve
  grins.run();

  // Get equation systems to create ExactSolution object
  //std::tr1::shared_ptr<libMesh::EquationSystems> es = grins.get_equation_system();

  // Create Exact solution object and attach exact solution quantities
  //libMesh::ExactSolution exact_sol(*es);

  //exact_sol.attach_exact_value(&exact_solution);
  //exact_sol.attach_exact_deriv(&exact_derivative);

  // Compute error and get it in various norms
  //exact_sol.compute_error("GRINS", "u");

  //double l2error = exact_sol.l2_error("GRINS", "u");
  //double h1error = exact_sol.h1_error("GRINS", "u");

  // Needs to change to 1 based on comparison
  int return_flag = 0;

  // if( l2error > 1.0e-9 || h1error > 1.0e-9 )
  //   {
  //     return_flag = 1;

  //     std::cout << "Tolerance exceeded for velocity in Poiseuille test." << std::endl
  // 		<< "l2 error = " << l2error << std::endl
  // 		<< "h1 error = " << h1error << std::endl;
  //   }

  // // Compute error and get it in various norms
  // exact_sol.compute_error("GRINS", "p");

  // l2error = exact_sol.l2_error("GRINS", "p");
  // h1error = exact_sol.h1_error("GRINS", "p");

  // if( l2error > 2.0e-9 || h1error > 2.0e-9 )
  //   {
  //     return_flag = 1;

  //     std::cout << "Tolerance exceeded for pressure in Poiseuille test." << std::endl
  // 		<< "l2 error = " << l2error << std::endl
  // 		<< "h1 error = " << h1error << std::endl;
  //   }

  return return_flag;
}

std::multimap< GRINS::PhysicsName, GRINS::DBCContainer > TurbulentBCFactory::build_dirichlet( )
{
  std::tr1::shared_ptr<libMesh::FunctionBase<libMesh::Number> > turbulent_inlet( new TurbulentBdyFunction(this->turbulent_bc_values) );

  GRINS::DBCContainer cont_u;
  cont_u.add_var_name( "u" );
  cont_u.add_bc_id( 3 );

  cont_u.set_func( turbulent_inlet );

  GRINS::DBCContainer cont_nu;
  cont_nu.add_var_name( "nu" );
  cont_nu.add_bc_id( 3 );

  cont_nu.set_func( turbulent_inlet );

  std::multimap< GRINS::PhysicsName, GRINS::DBCContainer > mymap;

  mymap.insert( std::pair<GRINS::PhysicsName, GRINS::DBCContainer >(GRINS::incompressible_navier_stokes,  cont_u) );

  mymap.insert( std::pair<GRINS::PhysicsName, GRINS::DBCContainer >(GRINS::spalart_allmaras,  cont_nu) );

  return mymap;
}

// libMesh::Number
// exact_solution( const libMesh::Point& p,
// 		const libMesh::Parameters&,   // parameters, not needed
// 		const std::string&,  // sys_name, not needed
// 		const std::string&); // unk_name, not needed);

// libMesh::Gradient
// exact_derivative( const libMesh::Point& p,
// 		  const libMesh::Parameters&,   // parameters, not needed
// 		  const std::string&,  // sys_name, not needed
// 		  const std::string&); // unk_name, not needed);

// libMesh::Number
// exact_solution( const libMesh::Point& p,
// 		const libMesh::Parameters& /*params*/,   // parameters, not needed
// 		const std::string& /*sys_name*/,  // sys_name, not needed
// 		const std::string& var )  // unk_name, not needed);
// {
//   const double x = p(0);
//   const double y = p(1);

//   libMesh::Number f = 0;
//   // Hardcoded to velocity in input file.
//   if( var == "u" ) f = 4*y*(1-y);
//   else if( var == "p" ) f = 120.0 + (80.0-120.0)/5.0*x;
//   else libmesh_assert(false);

//   return f;
// }

// libMesh::Gradient
// exact_derivative( const libMesh::Point& p,
// 		  const libMesh::Parameters& /*params*/,   // parameters, not needed
// 		  const std::string& /*sys_name*/,  // sys_name, not needed
// 		  const std::string& var)  // unk_name, not needed);
// {
//   const double y = p(1);

//   libMesh::Gradient g;

//   // Hardcoded to velocity in input file.
//   if( var == "u" )
//     {
//       g(0) = 0.0;
//       g(1) = 4*(1-y) - 4*y;

// #if LIBMESH_DIM > 2
//       g(2) = 0.0;
// #endif
//     }

//   if( var == "p" )
//     {
//       g(0) = (80.0-120.0)/5.0;
//       g(1) = 0.0;

// #if LIBMESH_DIM > 2
//       g(2) = 0.0;
// #endif
//     }
//   return g;
// }

<|endoftext|>


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

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

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkVolumeTextureMapper.h"
#include "vtkVolume.h"
#include "vtkRenderer.h"
#include "vtkFiniteDifferenceGradientEstimator.h"

vtkVolumeTextureMapper::vtkVolumeTextureMapper()
{
  this->ScalarOpacityArray      = NULL;
  this->GradientOpacityArray    = NULL;
  this->RGBArray                = NULL;
  this->GrayArray               = NULL;
  this->ArraySize               = -1;
  this->GradientOpacityConstant = 0.0;
  this->SampleDistance          = 1.0;
  this->GradientEstimator       = vtkFiniteDifferenceGradientEstimator::New();
  this->GradientShader          = vtkEncodedGradientShader::New();
}

vtkVolumeTextureMapper::~vtkVolumeTextureMapper()
{
  this->SetGradientEstimator( NULL );
  this->GradientShader->Delete();

  if ( this->ScalarOpacityArray )
    {
    delete [] this->ScalarOpacityArray;
    }

  if ( this->GrayArray )
    {
    delete [] this->GrayArray;
    }

  if ( this->RGBArray )
    {
    delete [] this->RGBArray;
    }
}

void vtkVolumeTextureMapper::SetGradientEstimator(
				      vtkEncodedGradientEstimator *gradest )
{

  // If we are setting it to its current value, don't do anything
  if ( this->GradientEstimator == gradest )
    {
    return;
    }

  // If we already have a gradient estimator, unregister it.
  if ( this->GradientEstimator )
    {
    this->GradientEstimator->UnRegister(this);
    this->GradientEstimator = NULL;
    }

  // If we are passing in a non-NULL estimator, register it
  if ( gradest )
    {
    gradest->Register( this );
    }

  // Actually set the estimator, and consider the object Modified
  this->GradientEstimator = gradest;
  this->Modified();
}

void vtkVolumeTextureMapper::Update()
{
  if ( this->GetInput() )
    {
    this->GetInput()->Update();
    }

  if ( this->GetRGBTextureInput() )
    {
    this->GetRGBTextureInput()->Update();
    }
}

void vtkVolumeTextureMapper::InitializeRender( vtkRenderer *ren,
					       vtkVolume *vol )
{
  int   size, i;
  float *tmpArray;
  int   colorChannels;

  // Hang on to the render window - we'll need it to test for abort
  this->RenderWindow = ren->GetRenderWindow();

  vol->UpdateTransferFunctions( ren );

  vol->UpdateScalarOpacityforSampleSize( ren, this->SampleDistance );

  colorChannels = vol->GetProperty()->GetColorChannels();

  size = vol->GetArraySize();

  if ( this->ArraySize != size )
    {
    if ( this->ScalarOpacityArray )
      {
      delete [] this->ScalarOpacityArray;
      }

    if ( this->RGBArray )
      {
      delete [] this->ScalarOpacityArray;
      }

    if ( this->GrayArray )
      {
      delete [] this->ScalarOpacityArray;
      }

    this->ScalarOpacityArray   = new unsigned char[size];
    this->RGBArray             = new unsigned char[3*size];
    this->GrayArray            = new unsigned char[size];

    this->ArraySize = size;
    }

  tmpArray = vol->GetCorrectedScalarOpacityArray();
  for ( i = 0; i < size; i++ )
    {
    this->ScalarOpacityArray[i] = tmpArray[i]*255.99;
    }

  this->GradientOpacityArray = vol->GetGradientOpacityArray();

  if ( colorChannels == 3 )
    {
    tmpArray = vol->GetRGBArray();
    for ( i = 0; i < 3*size; i++ )
      {
      this->RGBArray[i] = tmpArray[i]*255.99;
      }
    }
  else if ( colorChannels == 1 )
    {
    tmpArray = vol->GetGrayArray();
    for ( i = 0; i < size; i++ )
      {
      this->GrayArray[i] = tmpArray[i]*255.99;
      }
    }

  this->GradientOpacityConstant = vol->GetGradientOpacityConstant();

  this->Shade =  vol->GetProperty()->GetShade();

  this->GradientEstimator->SetInput( this->GetInput() );

  if ( this->Shade )
    {
    this->GradientShader->UpdateShadingTable( ren, vol,
					      this->GradientEstimator );
    this->EncodedNormals =
      this->GradientEstimator->GetEncodedNormals();

    this->RedDiffuseShadingTable =
      this->GradientShader->GetRedDiffuseShadingTable(vol);
    this->GreenDiffuseShadingTable =
      this->GradientShader->GetGreenDiffuseShadingTable(vol);
    this->BlueDiffuseShadingTable =
      this->GradientShader->GetBlueDiffuseShadingTable(vol);

    this->RedSpecularShadingTable =
      this->GradientShader->GetRedSpecularShadingTable(vol);
    this->GreenSpecularShadingTable =
      this->GradientShader->GetGreenSpecularShadingTable(vol);
    this->BlueSpecularShadingTable =
      this->GradientShader->GetBlueSpecularShadingTable(vol);
    }
  else
    {
    this->EncodedNormals = NULL;
    this->RedDiffuseShadingTable = NULL;
    this->GreenDiffuseShadingTable = NULL;
    this->BlueDiffuseShadingTable = NULL;
    this->RedSpecularShadingTable = NULL;
    this->GreenSpecularShadingTable = NULL;
    this->BlueSpecularShadingTable = NULL;
    }

  // If we have non-constant opacity on the gradient magnitudes,
  // we need to use the gradient magnitudes to look up the opacity
  if ( this->GradientOpacityConstant == -1.0 )
    {
    this->GradientMagnitudes =
      this->GradientEstimator->GetGradientMagnitudes();
    }
  else
    {
    this->GradientMagnitudes = NULL;
    }

  this->GetInput()->GetOrigin( this->DataOrigin );
  this->GetInput()->GetSpacing( this->DataSpacing );
}

// Print the vtkVolumeTextureMapper
void vtkVolumeTextureMapper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->vtkVolumeMapper::PrintSelf(os,indent);

  if ( this->GradientEstimator )
    {
      os << indent << "Gradient Estimator: " << (this->GradientEstimator) <<
	endl;
    }
  else
    {
      os << indent << "Gradient Estimator: (none)" << endl;
    }

  if ( this->GradientShader )
    {
      os << indent << "Gradient Shader: " << (this->GradientShader) << endl;
    }
  else
    {
      os << indent << "Gradient Shader: (none)" << endl;
    }

  // this->Shade is a temporary variable that should not be printed
}
<commit_msg>Added some comments to get around PrintSelf defects.<commit_after>/*=========================================================================

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

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkVolumeTextureMapper.h"
#include "vtkVolume.h"
#include "vtkRenderer.h"
#include "vtkFiniteDifferenceGradientEstimator.h"

vtkVolumeTextureMapper::vtkVolumeTextureMapper()
{
  this->ScalarOpacityArray      = NULL;
  this->GradientOpacityArray    = NULL;
  this->RGBArray                = NULL;
  this->GrayArray               = NULL;
  this->ArraySize               = -1;
  this->GradientOpacityConstant = 0.0;
  this->SampleDistance          = 1.0;
  this->GradientEstimator       = vtkFiniteDifferenceGradientEstimator::New();
  this->GradientShader          = vtkEncodedGradientShader::New();
}

vtkVolumeTextureMapper::~vtkVolumeTextureMapper()
{
  this->SetGradientEstimator( NULL );
  this->GradientShader->Delete();

  if ( this->ScalarOpacityArray )
    {
    delete [] this->ScalarOpacityArray;
    }

  if ( this->GrayArray )
    {
    delete [] this->GrayArray;
    }

  if ( this->RGBArray )
    {
    delete [] this->RGBArray;
    }
}

void vtkVolumeTextureMapper::SetGradientEstimator(
				      vtkEncodedGradientEstimator *gradest )
{

  // If we are setting it to its current value, don't do anything
  if ( this->GradientEstimator == gradest )
    {
    return;
    }

  // If we already have a gradient estimator, unregister it.
  if ( this->GradientEstimator )
    {
    this->GradientEstimator->UnRegister(this);
    this->GradientEstimator = NULL;
    }

  // If we are passing in a non-NULL estimator, register it
  if ( gradest )
    {
    gradest->Register( this );
    }

  // Actually set the estimator, and consider the object Modified
  this->GradientEstimator = gradest;
  this->Modified();
}

void vtkVolumeTextureMapper::Update()
{
  if ( this->GetInput() )
    {
    this->GetInput()->Update();
    }

  if ( this->GetRGBTextureInput() )
    {
    this->GetRGBTextureInput()->Update();
    }
}

void vtkVolumeTextureMapper::InitializeRender( vtkRenderer *ren,
					       vtkVolume *vol )
{
  int   size, i;
  float *tmpArray;
  int   colorChannels;

  // Hang on to the render window - we'll need it to test for abort
  this->RenderWindow = ren->GetRenderWindow();

  vol->UpdateTransferFunctions( ren );

  vol->UpdateScalarOpacityforSampleSize( ren, this->SampleDistance );

  colorChannels = vol->GetProperty()->GetColorChannels();

  size = vol->GetArraySize();

  if ( this->ArraySize != size )
    {
    if ( this->ScalarOpacityArray )
      {
      delete [] this->ScalarOpacityArray;
      }

    if ( this->RGBArray )
      {
      delete [] this->ScalarOpacityArray;
      }

    if ( this->GrayArray )
      {
      delete [] this->ScalarOpacityArray;
      }

    this->ScalarOpacityArray   = new unsigned char[size];
    this->RGBArray             = new unsigned char[3*size];
    this->GrayArray            = new unsigned char[size];

    this->ArraySize = size;
    }

  tmpArray = vol->GetCorrectedScalarOpacityArray();
  for ( i = 0; i < size; i++ )
    {
    this->ScalarOpacityArray[i] = tmpArray[i]*255.99;
    }

  this->GradientOpacityArray = vol->GetGradientOpacityArray();

  if ( colorChannels == 3 )
    {
    tmpArray = vol->GetRGBArray();
    for ( i = 0; i < 3*size; i++ )
      {
      this->RGBArray[i] = tmpArray[i]*255.99;
      }
    }
  else if ( colorChannels == 1 )
    {
    tmpArray = vol->GetGrayArray();
    for ( i = 0; i < size; i++ )
      {
      this->GrayArray[i] = tmpArray[i]*255.99;
      }
    }

  this->GradientOpacityConstant = vol->GetGradientOpacityConstant();

  this->Shade =  vol->GetProperty()->GetShade();

  this->GradientEstimator->SetInput( this->GetInput() );

  if ( this->Shade )
    {
    this->GradientShader->UpdateShadingTable( ren, vol,
					      this->GradientEstimator );
    this->EncodedNormals =
      this->GradientEstimator->GetEncodedNormals();

    this->RedDiffuseShadingTable =
      this->GradientShader->GetRedDiffuseShadingTable(vol);
    this->GreenDiffuseShadingTable =
      this->GradientShader->GetGreenDiffuseShadingTable(vol);
    this->BlueDiffuseShadingTable =
      this->GradientShader->GetBlueDiffuseShadingTable(vol);

    this->RedSpecularShadingTable =
      this->GradientShader->GetRedSpecularShadingTable(vol);
    this->GreenSpecularShadingTable =
      this->GradientShader->GetGreenSpecularShadingTable(vol);
    this->BlueSpecularShadingTable =
      this->GradientShader->GetBlueSpecularShadingTable(vol);
    }
  else
    {
    this->EncodedNormals = NULL;
    this->RedDiffuseShadingTable = NULL;
    this->GreenDiffuseShadingTable = NULL;
    this->BlueDiffuseShadingTable = NULL;
    this->RedSpecularShadingTable = NULL;
    this->GreenSpecularShadingTable = NULL;
    this->BlueSpecularShadingTable = NULL;
    }

  // If we have non-constant opacity on the gradient magnitudes,
  // we need to use the gradient magnitudes to look up the opacity
  if ( this->GradientOpacityConstant == -1.0 )
    {
    this->GradientMagnitudes =
      this->GradientEstimator->GetGradientMagnitudes();
    }
  else
    {
    this->GradientMagnitudes = NULL;
    }

  this->GetInput()->GetOrigin( this->DataOrigin );
  this->GetInput()->GetSpacing( this->DataSpacing );
}

// Print the vtkVolumeTextureMapper
void vtkVolumeTextureMapper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->vtkVolumeMapper::PrintSelf(os,indent);

  if ( this->GradientEstimator )
    {
      os << indent << "Gradient Estimator: " << (this->GradientEstimator) <<
	endl;
    }
  else
    {
      os << indent << "Gradient Estimator: (none)" << endl;
    }

  if ( this->GradientShader )
    {
      os << indent << "Gradient Shader: " << (this->GradientShader) << endl;
    }
  else
    {
      os << indent << "Gradient Shader: (none)" << endl;
    }

  // this->Shade is a temporary variable that should not be printed
  // this->RenderWindow is a temporary variable that should not be printed
  // this->DataSpacing is a temporary variable that should not be printed
  // this->DataOrigin is a temporary variable that should not be printed
}
<|endoftext|>


<commit_before>#include <RenHook/RenHook.hpp>
#include <RenHook/Hooks/Hook.hpp>
#include <RenHook/Memory/Protection.hpp>
#include <RenHook/Threads/Threads.hpp>

RenHook::Hook::Hook(const uintptr_t Address, const uintptr_t Detour)
    : m_address(Address)
{
    RenHook::Managers::Threads Threads;
    Threads.Suspend();

    m_size = GetMinimumSize(Address);
    m_memoryBlock = std::make_unique<RenHook::Memory::Block>(Address, m_size);

    // Backup the original bytes.
    m_memoryBlock->CopyFrom(Address, m_size);

    Memory::Protection Protection(Address, m_size);
    Protection.Change(PAGE_EXECUTE_READWRITE);

    // TODO: Check for relative jumps and fix them.

    //auto HookSize = WriteJump(Address, Detour, m_size);

    // Jump back to the original code (16 bytes).
    //WriteJump(m_memoryBlock.GetAddress() + m_size, Address + m_size, 16);

    // Set unused bytes as NOP.
    //if (HookSize < m_size)
    {
        //std::memset(reinterpret_cast<uintptr_t*>(Address + HookSize), 0x90, m_size - HookSize);
    }

    Protection.Restore();
    Threads.Resume();
}

RenHook::Hook::~Hook()
{
    RenHook::Managers::Threads Threads;
    Threads.Suspend();

    Memory::Protection Protection(m_address, m_size);
    Protection.Change(PAGE_EXECUTE_READWRITE);

    // Restore the original bytes.
    m_memoryBlock->CopyTo(m_address, m_size);

    Protection.Restore();
    Threads.Resume();
}

std::shared_ptr<RenHook::Hook> RenHook::Hook::Get(const uintptr_t Address)
{
    return RenHook::Managers::Hooks::Get(Address);
}

std::shared_ptr<RenHook::Hook> RenHook::Hook::Get(const std::wstring& Key)
{
    return RenHook::Managers::Hooks::Get(Key);
}

std::shared_ptr<RenHook::Hook> RenHook::Hook::Get(const std::wstring& Module, const std::wstring& Function)
{
    return RenHook::Managers::Hooks::Get(Module, Function);
}

void RenHook::Hook::Remove(const uintptr_t Address)
{
    return RenHook::Managers::Hooks::Remove(Address);
}

void RenHook::Hook::Remove(const std::wstring& Key)
{
    return RenHook::Managers::Hooks::Remove(Key);
}

void RenHook::Hook::Remove(const std::wstring& Module, const std::wstring& Function)
{
    return RenHook::Managers::Hooks::Remove(Module, Function);
}

const size_t RenHook::Hook::CheckSize(const RenHook::Capstone& Capstone, const size_t MinimumSize) const
{
    size_t Result = 0;

    for (size_t i = 0; i < Capstone.GetTotalNumberOfInstruction(); i++)
    {
        Result += Capstone.GetInstructionSize(i);

        if (Result >= MinimumSize)
        {
            break;
        }
    }

    return Result >= MinimumSize ? Result : 0;
}

const size_t RenHook::Hook::GetMinimumSize(const uintptr_t Address) const
{
    size_t Length = 0;

    RenHook::Capstone Capstone;
    Capstone.Disassemble(Address, 128);

    // Check if we can do a 16 byte jump.
    Length = CheckSize(Capstone, 16);

    // Check if we can do a 6 byte jump if we can't do a 16 byte jump.
    if (Length == 0)
    {
        Length = CheckSize(Capstone, 6);

        // Check if we can do a 5 byte jump if we can't do a 6 byte jump.
        if (Length == 0)
        {
            Length = CheckSize(Capstone, 5);
        }
    }

    return Length;
}

const size_t RenHook::Hook::WriteJump(const uintptr_t Address, const uintptr_t Detour, const size_t Size) const
{
    std::vector<uint8_t> Bytes;

    // Should we do a x64 or x86 jump?
    if (Size >= 16)
    {
        /*
        * push rax
        * mov rax, 0xCCCCCCCCCCCCCCCC
        * xchg rax, [rsp]
        * ret
        */
        Bytes = { 0x50, 0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x48, 0x87, 0x04, 0x24, 0xC3 };

        // Set our detour function.
        *reinterpret_cast<uintptr_t*>(Bytes.data() + 3) = Detour;
    }
    else
    {
        // If the displacement is less than 2048 MB do a near jump or if the hook size is equal with 5, otherwise do a far jump.
        if (std::abs(reinterpret_cast<uintptr_t*>(Address) - reinterpret_cast<uintptr_t*>(Detour)) <= 0x7fff0000 || Size == 5)
        {
            /*
            * jmp 0xCCCCCCCC
            */
            Bytes = { 0xE9, 0xCC, 0xCC, 0xCC, 0xCC };

            // Set our detour function.
            *reinterpret_cast<int32_t*>(Bytes.data() + 1) = CalculateDisplacement<int32_t>(Address, Detour, Bytes.size());
        }
        else
        {
            /*
            * jmp qword ptr ds:[0xCCCCCCCC]
            */
            Bytes = { 0xFF, 0x25, 0xCC, 0xCC, 0xCC, 0xCC };

            // Add the displacement right after our jump back to the original function which is located at "m_memoryBlock.GetAddress() + Size" and has a size of 16 bytes.
            auto Displacement = m_memoryBlock->GetAddress() + Size + 17;

            // Write the address in memory at RIP + Displacement.
            *reinterpret_cast<uintptr_t*>(Displacement) = Detour;

            // Set our detour function.
            *reinterpret_cast<int32_t*>(Bytes.data() + 2) = CalculateDisplacement<int32_t>(Address, Displacement, Bytes.size());
        }
    }

    // Calculate the hook size in bytes.
    auto HookSize = sizeof(uint8_t) * Bytes.size();

    // Override the original bytes.
    std::memcpy(reinterpret_cast<uintptr_t*>(Address), Bytes.data(), HookSize);

    return HookSize;
}<commit_msg>Write jump instructions<commit_after>#include <RenHook/RenHook.hpp>
#include <RenHook/Hooks/Hook.hpp>
#include <RenHook/Memory/Protection.hpp>
#include <RenHook/Threads/Threads.hpp>

RenHook::Hook::Hook(const uintptr_t Address, const uintptr_t Detour)
    : m_address(Address)
{
    RenHook::Managers::Threads Threads;
    Threads.Suspend();

    m_size = GetMinimumSize(Address);
    m_memoryBlock = std::make_unique<RenHook::Memory::Block>(Address, m_size);

    // Backup the original bytes.
    m_memoryBlock->CopyFrom(Address, m_size);

    Memory::Protection Protection(Address, m_size);
    Protection.Change(PAGE_EXECUTE_READWRITE);

    // TODO: Check for relative jumps and fix them.

    auto HookSize = WriteJump(Address, Detour, m_size);

    // Jump back to the original code (16 bytes).
    WriteJump(m_memoryBlock->GetAddress() + m_size, Address + m_size, 16);

    // Set unused bytes as NOP.
    if (HookSize < m_size)
    {
        std::memset(reinterpret_cast<uintptr_t*>(Address + HookSize), 0x90, m_size - HookSize);
    }

    Protection.Restore();
    Threads.Resume();
}

RenHook::Hook::~Hook()
{
    RenHook::Managers::Threads Threads;
    Threads.Suspend();

    Memory::Protection Protection(m_address, m_size);
    Protection.Change(PAGE_EXECUTE_READWRITE);

    // Restore the original bytes.
    m_memoryBlock->CopyTo(m_address, m_size);

    Protection.Restore();
    Threads.Resume();
}

std::shared_ptr<RenHook::Hook> RenHook::Hook::Get(const uintptr_t Address)
{
    return RenHook::Managers::Hooks::Get(Address);
}

std::shared_ptr<RenHook::Hook> RenHook::Hook::Get(const std::wstring& Key)
{
    return RenHook::Managers::Hooks::Get(Key);
}

std::shared_ptr<RenHook::Hook> RenHook::Hook::Get(const std::wstring& Module, const std::wstring& Function)
{
    return RenHook::Managers::Hooks::Get(Module, Function);
}

void RenHook::Hook::Remove(const uintptr_t Address)
{
    return RenHook::Managers::Hooks::Remove(Address);
}

void RenHook::Hook::Remove(const std::wstring& Key)
{
    return RenHook::Managers::Hooks::Remove(Key);
}

void RenHook::Hook::Remove(const std::wstring& Module, const std::wstring& Function)
{
    return RenHook::Managers::Hooks::Remove(Module, Function);
}

const size_t RenHook::Hook::CheckSize(const RenHook::Capstone& Capstone, const size_t MinimumSize) const
{
    size_t Result = 0;

    for (size_t i = 0; i < Capstone.GetTotalNumberOfInstruction(); i++)
    {
        Result += Capstone.GetInstructionSize(i);

        if (Result >= MinimumSize)
        {
            break;
        }
    }

    return Result >= MinimumSize ? Result : 0;
}

const size_t RenHook::Hook::GetMinimumSize(const uintptr_t Address) const
{
    size_t Length = 0;

    RenHook::Capstone Capstone;
    Capstone.Disassemble(Address, 128);

    // Check if we can do a 16 byte jump.
    Length = CheckSize(Capstone, 16);

    // Check if we can do a 6 byte jump if we can't do a 16 byte jump.
    if (Length == 0)
    {
        Length = CheckSize(Capstone, 6);

        // Check if we can do a 5 byte jump if we can't do a 6 byte jump.
        if (Length == 0)
        {
            Length = CheckSize(Capstone, 5);
        }
    }

    return Length;
}

const size_t RenHook::Hook::WriteJump(const uintptr_t Address, const uintptr_t Detour, const size_t Size) const
{
    std::vector<uint8_t> Bytes;

    // Should we do a x64 or x86 jump?
    if (Size >= 16)
    {
        /*
        * push rax
        * mov rax, 0xCCCCCCCCCCCCCCCC
        * xchg rax, [rsp]
        * ret
        */
        Bytes = { 0x50, 0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x48, 0x87, 0x04, 0x24, 0xC3 };

        // Set our detour function.
        *reinterpret_cast<uintptr_t*>(Bytes.data() + 3) = Detour;
    }
    else
    {
        // If the displacement is less than 2048 MB do a near jump or if the hook size is equal with 5, otherwise do a far jump.
        if (std::abs(reinterpret_cast<uintptr_t*>(Address) - reinterpret_cast<uintptr_t*>(Detour)) <= 0x7fff0000 || Size == 5)
        {
            /*
            * jmp 0xCCCCCCCC
            */
            Bytes = { 0xE9, 0xCC, 0xCC, 0xCC, 0xCC };

            // Set our detour function.
            *reinterpret_cast<int32_t*>(Bytes.data() + 1) = CalculateDisplacement<int32_t>(Address, Detour, Bytes.size());
        }
        else
        {
            /*
            * jmp qword ptr ds:[0xCCCCCCCC]
            */
            Bytes = { 0xFF, 0x25, 0xCC, 0xCC, 0xCC, 0xCC };

            // Add the displacement right after our jump back to the original function which is located at "m_memoryBlock.GetAddress() + Size" and has a size of 16 bytes.
            auto Displacement = m_memoryBlock->GetAddress() + Size + 17;

            // Write the address in memory at RIP + Displacement.
            *reinterpret_cast<uintptr_t*>(Displacement) = Detour;

            // Set our detour function.
            *reinterpret_cast<int32_t*>(Bytes.data() + 2) = CalculateDisplacement<int32_t>(Address, Displacement, Bytes.size());
        }
    }

    // Calculate the hook size in bytes.
    auto HookSize = sizeof(uint8_t) * Bytes.size();

    // Override the original bytes.
    std::memcpy(reinterpret_cast<uintptr_t*>(Address), Bytes.data(), HookSize);

    return HookSize;
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: MNameMapper.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: obo $ $Date: 2004-03-17 10:42:36 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Darren Kenny
 *
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_MAB_NAMEMAPPER_HXX_
#define _CONNECTIVITY_MAB_NAMEMAPPER_HXX_ 1

#include <map>

// Mozilla includes
#include <MNSInclude.hxx>

// Star Includes
#include <rtl/ustring.hxx>

namespace connectivity
{
    namespace mozab
    {
        class MNameMapper
        {
            private:

                struct ltstr
                {
                    bool operator()( const ::rtl::OUString &s1, const ::rtl::OUString &s2) const;
                };

                typedef ::std::multimap< ::rtl::OUString, nsIAbDirectory *, ltstr > dirMap;
                typedef ::std::multimap< ::rtl::OUString, nsIAbDirectory *, ltstr > uriMap;

                static MNameMapper    *instance;
                dirMap                     *mDirMap;
                uriMap                     *mUriMap;

                //clear dirs
                void clear();

            public:
                static MNameMapper* getInstance();

                MNameMapper();
                ~MNameMapper();

                // May modify the name passed in so that it's unique
                nsresult add( ::rtl::OUString& str, nsIAbDirectory* abook );

                //reset dirs
                void reset();

                // Will replace the given dir
                void replace( const ::rtl::OUString& str, nsIAbDirectory* abook );

                // Get the directory corresponding to str
                bool getDir( const ::rtl::OUString& str, nsIAbDirectory* *abook );

        };

    }
}

#endif //_CONNECTIVITY_MAB_NAMEMAPPER_HXX_
<commit_msg>INTEGRATION: CWS mozab04 (1.2.2); FILE MERGED 2004/04/12 10:15:55 windly 1.2.2.1: #i6883# make mozab driver threadsafe<commit_after>/*************************************************************************
 *
 *  $RCSfile: MNameMapper.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hjs $ $Date: 2004-06-25 18:33:16 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Darren Kenny
 *
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_MAB_NAMEMAPPER_HXX_
#define _CONNECTIVITY_MAB_NAMEMAPPER_HXX_ 1

#include <map>

// Mozilla includes
#include <MNSInclude.hxx>

// Star Includes
#include <rtl/ustring.hxx>

namespace connectivity
{
    namespace mozab
    {
        class MNameMapper
        {
            private:

                struct ltstr
                {
                    bool operator()( const ::rtl::OUString &s1, const ::rtl::OUString &s2) const;
                };

                typedef ::std::multimap< ::rtl::OUString, nsIAbDirectory *, ltstr > dirMap;
                typedef ::std::multimap< ::rtl::OUString, nsIAbDirectory *, ltstr > uriMap;

                static MNameMapper    *instance;
                dirMap                     *mDirMap;
                uriMap                     *mUriMap;

                //clear dirs
                void clear();

            public:
                static MNameMapper* getInstance();

                MNameMapper();
                ~MNameMapper();

                // May modify the name passed in so that it's unique
                nsresult add( ::rtl::OUString& str, nsIAbDirectory* abook );

                //reset dirs
                void reset();

                // Will replace the given dir
                void replace( const ::rtl::OUString& str, nsIAbDirectory* abook );

                // Get the directory corresponding to str
                bool getDir( const ::rtl::OUString& str, nsIAbDirectory* *abook );

        };

    }
}

#endif //_CONNECTIVITY_MAB_NAMEMAPPER_HXX_
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scrwnd.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2007-04-26 09:30:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <math.h>
#include <limits.h>

#ifndef _TOOLS_TIME_HXX
#include <tools/time.hxx>
#endif
#include <tools/debug.hxx>

#ifndef _SV_SVIDS_HRC
#include <svids.hrc>
#endif
#ifndef _SV_SVDATA_HXX
#include <svdata.hxx>
#endif
#ifndef _VCL_TIMER_HXX
#include <timer.hxx>
#endif
#ifndef _VCL_EVENT_HXX
#include <event.hxx>
#endif
#ifndef _VCL_SCRWND_HXX
#include <scrwnd.hxx>
#endif

// -----------
// - Defines -
// -----------

#define WHEEL_WIDTH     25
#define WHEEL_RADIUS    ((WHEEL_WIDTH) >> 1 )
#define MAX_TIME        300
#define MIN_TIME        20
#define DEF_TIMEOUT     50

// -------------------
// - ImplWheelWindow -
// -------------------

ImplWheelWindow::ImplWheelWindow( Window* pParent ) :
            FloatingWindow  ( pParent, 0 ),
            mnRepaintTime   ( 1UL ),
            mnTimeout       ( DEF_TIMEOUT ),
            mnWheelMode     ( WHEELMODE_NONE ),
            mnActDist       ( 0UL ),
            mnActDeltaX     ( 0L ),
            mnActDeltaY     ( 0L )
{
    // we need a parent
    DBG_ASSERT( pParent, "ImplWheelWindow::ImplWheelWindow(): Parent not set!" );

    const Size      aSize( pParent->GetOutputSizePixel() );
    const USHORT    nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL      bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL      bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;

    // calculate maximum speed distance
    mnMaxWidth = (ULONG) ( 0.4 * hypot( (double) aSize.Width(), aSize.Height() ) );

    // create wheel window
    SetTitleType( FLOATWIN_TITLE_NONE );
    ImplCreateImageList();
    ResMgr* pResMgr = ImplGetResMgr();
    Bitmap aBmp;
    if( pResMgr )
        aBmp = Bitmap( ResId( SV_RESID_BITMAP_SCROLLMSK, *pResMgr ) );
    ImplSetRegion( aBmp );

    // set wheel mode
    if( bHorz && bVert )
        ImplSetWheelMode( WHEELMODE_VH );
    else if( bHorz )
        ImplSetWheelMode( WHEELMODE_H );
    else
        ImplSetWheelMode( WHEELMODE_V );

    // init timer
    mpTimer = new Timer;
    mpTimer->SetTimeoutHdl( LINK( this, ImplWheelWindow, ImplScrollHdl ) );
    mpTimer->SetTimeout( mnTimeout );
    mpTimer->Start();

    CaptureMouse();
}

// ------------------------------------------------------------------------

ImplWheelWindow::~ImplWheelWindow()
{
    ImplStop();
    delete mpTimer;
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplStop()
{
    ReleaseMouse();
    mpTimer->Stop();
    Show(FALSE);
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplSetRegion( const Bitmap& rRegionBmp )
{
    Point           aPos( GetPointerPosPixel() );
    const Size      aSize( rRegionBmp.GetSizePixel() );
    Point           aPoint;
    const Rectangle aRect( aPoint, aSize );

    maCenter = maLastMousePos = aPos;
    aPos.X() -= aSize.Width() >> 1;
    aPos.Y() -= aSize.Height() >> 1;

    SetPosSizePixel( aPos, aSize );
    SetWindowRegionPixel( rRegionBmp.CreateRegion( COL_BLACK, aRect ) );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplCreateImageList()
{
    Bitmap aImgBmp;
    ResMgr* pResMgr = ImplGetResMgr();
    if( pResMgr )
        aImgBmp = Bitmap( ResId( SV_RESID_BITMAP_SCROLLBMP, *pResMgr ) );
    maImgList = ImageList( aImgBmp, 6 );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplSetWheelMode( ULONG nWheelMode )
{
    if( nWheelMode != mnWheelMode )
    {
        mnWheelMode = nWheelMode;

        if( WHEELMODE_NONE == mnWheelMode )
        {
            if( IsVisible() )
                Hide();
        }
        else
        {
            if( !IsVisible() )
                Show();

            ImplDrawWheel();
        }
    }
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplDrawWheel()
{
    USHORT nId;

    switch( mnWheelMode )
    {
        case( WHEELMODE_VH ):       nId = 1; break;
        case( WHEELMODE_V    ):     nId = 2; break;
        case( WHEELMODE_H    ):     nId = 3; break;
        case( WHEELMODE_SCROLL_VH ):nId = 4; break;
        case( WHEELMODE_SCROLL_V ): nId = 5; break;
        case( WHEELMODE_SCROLL_H ): nId = 6; break;
        default:                    nId = 0; break;
    }

    if( nId )
        DrawImage( Point(), maImgList.GetImage( nId ) );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplRecalcScrollValues()
{
    if( mnActDist < WHEEL_RADIUS )
    {
        mnActDeltaX = mnActDeltaY = 0L;
        mnTimeout = DEF_TIMEOUT;
    }
    else
    {
        ULONG nCurTime;

        // calc current time
        if( mnMaxWidth )
        {
            const double fExp = ( (double) mnActDist / mnMaxWidth ) * log10( (double) MAX_TIME / MIN_TIME );
            nCurTime = (ULONG) ( MAX_TIME / pow( 10., fExp ) );
        }
        else
            nCurTime = MAX_TIME;

        if( !nCurTime )
            nCurTime = 1UL;

        if( mnRepaintTime <= nCurTime )
            mnTimeout = nCurTime - mnRepaintTime;
        else
        {
            long nMult = mnRepaintTime / nCurTime;

            if( !( mnRepaintTime % nCurTime ) )
                mnTimeout = 0UL;
            else
                mnTimeout = ++nMult * nCurTime - mnRepaintTime;

            double fValX = (double) mnActDeltaX * nMult;
            double fValY = (double) mnActDeltaY * nMult;

            if( fValX > LONG_MAX )
                mnActDeltaX = LONG_MAX;
            else if( fValX < LONG_MIN )
                mnActDeltaX = LONG_MIN;
            else
                mnActDeltaX = (long) fValX;

            if( fValY > LONG_MAX )
                mnActDeltaY = LONG_MAX;
            else if( fValY < LONG_MIN )
                mnActDeltaY = LONG_MIN;
            else
                mnActDeltaY = (long) fValY;
        }
    }
}

// ------------------------------------------------------------------------

PointerStyle ImplWheelWindow::ImplGetMousePointer( long nDistX, long nDistY )
{
    PointerStyle    eStyle;
    const USHORT    nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL      bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL      bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;

    if( bHorz || bVert )
    {
        if( mnActDist < WHEEL_RADIUS )
        {
            if( bHorz && bVert )
                eStyle = POINTER_AUTOSCROLL_NSWE;
            else if( bHorz )
                eStyle = POINTER_AUTOSCROLL_WE;
            else
                eStyle = POINTER_AUTOSCROLL_NS;
        }
        else
        {
            double fAngle = atan2( (double) -nDistY, nDistX ) / F_PI180;

            if( fAngle < 0.0 )
                fAngle += 360.;

            if( bHorz && bVert )
            {
                if( fAngle >= 22.5 && fAngle <= 67.5 )
                    eStyle = POINTER_AUTOSCROLL_NE;
                else if( fAngle >= 67.5 && fAngle <= 112.5 )
                    eStyle = POINTER_AUTOSCROLL_N;
                else if( fAngle >= 112.5 && fAngle <= 157.5 )
                    eStyle = POINTER_AUTOSCROLL_NW;
                else if( fAngle >= 157.5 && fAngle <= 202.5 )
                    eStyle = POINTER_AUTOSCROLL_W;
                else if( fAngle >= 202.5 && fAngle <= 247.5 )
                    eStyle = POINTER_AUTOSCROLL_SW;
                else if( fAngle >= 247.5 && fAngle <= 292.5 )
                    eStyle = POINTER_AUTOSCROLL_S;
                else if( fAngle >= 292.5 && fAngle <= 337.5 )
                    eStyle = POINTER_AUTOSCROLL_SE;
                else
                    eStyle = POINTER_AUTOSCROLL_E;
            }
            else if( bHorz )
            {
                if( fAngle >= 270. || fAngle <= 90. )
                    eStyle = POINTER_AUTOSCROLL_E;
                else
                    eStyle = POINTER_AUTOSCROLL_W;
            }
            else
            {
                if( fAngle >= 0. && fAngle <= 180. )
                    eStyle = POINTER_AUTOSCROLL_N;
                else
                    eStyle = POINTER_AUTOSCROLL_S;
            }
        }
    }
    else
        eStyle = POINTER_ARROW;

    return eStyle;
}

// ------------------------------------------------------------------------

void ImplWheelWindow::Paint( const Rectangle& )
{
    ImplDrawWheel();
}

// ------------------------------------------------------------------------

void ImplWheelWindow::MouseMove( const MouseEvent& rMEvt )
{
    FloatingWindow::MouseMove( rMEvt );

    const Point aMousePos( OutputToScreenPixel( rMEvt.GetPosPixel() ) );
    const long  nDistX = aMousePos.X() - maCenter.X();
    const long  nDistY = aMousePos.Y() - maCenter.Y();

    mnActDist = (ULONG) hypot( (double) nDistX, nDistY );

    const PointerStyle  eActStyle = ImplGetMousePointer( nDistX, nDistY );
    const USHORT        nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL          bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL          bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;
    const BOOL          bOuter = mnActDist > WHEEL_RADIUS;

    if( bOuter && ( maLastMousePos != aMousePos ) )
    {
        switch( eActStyle )
        {
            case( POINTER_AUTOSCROLL_N ):   mnActDeltaX = +0L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_S ):   mnActDeltaX = +0L, mnActDeltaY = -1L; break;
            case( POINTER_AUTOSCROLL_W ):   mnActDeltaX = +1L, mnActDeltaY = +0L; break;
            case( POINTER_AUTOSCROLL_E ):   mnActDeltaX = -1L, mnActDeltaY = +0L; break;
            case( POINTER_AUTOSCROLL_NW ):  mnActDeltaX = +1L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_NE ):  mnActDeltaX = -1L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_SW ):  mnActDeltaX = +1L, mnActDeltaY = -1L; break;
            case( POINTER_AUTOSCROLL_SE ):  mnActDeltaX = -1L, mnActDeltaY = -1L; break;

            default:
            break;
        }
    }

    ImplRecalcScrollValues();
    maLastMousePos = aMousePos;
    SetPointer( eActStyle );

    if( bHorz && bVert )
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_VH : WHEELMODE_VH );
    else if( bHorz )
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_H : WHEELMODE_H );
    else
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_V : WHEELMODE_V );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::MouseButtonUp( const MouseEvent& rMEvt )
{
    if( mnActDist > WHEEL_RADIUS )
        GetParent()->EndAutoScroll();
    else
        FloatingWindow::MouseButtonUp( rMEvt );
}

// ------------------------------------------------------------------------

IMPL_LINK( ImplWheelWindow, ImplScrollHdl, Timer*, EMPTYARG )
{
    if ( mnActDeltaX || mnActDeltaY )
    {
        Window*             pWindow = GetParent();
        const Point         aMousePos( pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() ) );
        Point               aCmdMousePos( pWindow->ImplFrameToOutput( aMousePos ) );
        CommandScrollData   aScrollData( mnActDeltaX, mnActDeltaY );
        CommandEvent        aCEvt( aCmdMousePos, COMMAND_AUTOSCROLL, TRUE, &aScrollData );
        NotifyEvent         aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );

        if ( !ImplCallPreNotify( aNCmdEvt ) )
        {
            const ULONG nTime = Time::GetSystemTicks();
            ImplDelData aDel( this );
            pWindow->Command( aCEvt );
            if( aDel.IsDead() )
                return 0;
            mnRepaintTime = Max( Time::GetSystemTicks() - nTime, 1UL );
            ImplRecalcScrollValues();
        }
    }

    if ( mnTimeout != mpTimer->GetTimeout() )
        mpTimer->SetTimeout( mnTimeout );
    mpTimer->Start();

    return 0L;
}
<commit_msg>INTEGRATION: CWS ka009 (1.7.36); FILE MERGED 2007/06/06 13:15:05 ka 1.7.36.3: resolved conflicts 2006/10/13 16:39:37 ka 1.7.36.2: RESYNC: (1.7-1.8); FILE MERGED 2006/07/12 22:03:53 ka 1.7.36.1: #i66680#: added patch for optimized ImageList handling<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scrwnd.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: ihi $ $Date: 2007-06-06 14:21:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <math.h>
#include <limits.h>

#ifndef _TOOLS_TIME_HXX
#include <tools/time.hxx>
#endif
#include <tools/debug.hxx>

#ifndef _SV_SVIDS_HRC
#include <svids.hrc>
#endif
#ifndef _SV_SVDATA_HXX
#include <svdata.hxx>
#endif
#ifndef _VCL_TIMER_HXX
#include <timer.hxx>
#endif
#ifndef _VCL_EVENT_HXX
#include <event.hxx>
#endif
#ifndef _VCL_SCRWND_HXX
#include <scrwnd.hxx>
#endif

// -----------
// - Defines -
// -----------

#define WHEEL_WIDTH     25
#define WHEEL_RADIUS    ((WHEEL_WIDTH) >> 1 )
#define MAX_TIME        300
#define MIN_TIME        20
#define DEF_TIMEOUT     50

// -------------------
// - ImplWheelWindow -
// -------------------

ImplWheelWindow::ImplWheelWindow( Window* pParent ) :
            FloatingWindow  ( pParent, 0 ),
            mnRepaintTime   ( 1UL ),
            mnTimeout       ( DEF_TIMEOUT ),
            mnWheelMode     ( WHEELMODE_NONE ),
            mnActDist       ( 0UL ),
            mnActDeltaX     ( 0L ),
            mnActDeltaY     ( 0L )
{
    // we need a parent
    DBG_ASSERT( pParent, "ImplWheelWindow::ImplWheelWindow(): Parent not set!" );

    const Size      aSize( pParent->GetOutputSizePixel() );
    const USHORT    nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL      bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL      bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;

    // calculate maximum speed distance
    mnMaxWidth = (ULONG) ( 0.4 * hypot( (double) aSize.Width(), aSize.Height() ) );

    // create wheel window
    SetTitleType( FLOATWIN_TITLE_NONE );
    ImplCreateImageList();
    ResMgr* pResMgr = ImplGetResMgr();
    Bitmap aBmp;
    if( pResMgr )
        aBmp = Bitmap( ResId( SV_RESID_BITMAP_SCROLLMSK, *pResMgr ) );
    ImplSetRegion( aBmp );

    // set wheel mode
    if( bHorz && bVert )
        ImplSetWheelMode( WHEELMODE_VH );
    else if( bHorz )
        ImplSetWheelMode( WHEELMODE_H );
    else
        ImplSetWheelMode( WHEELMODE_V );

    // init timer
    mpTimer = new Timer;
    mpTimer->SetTimeoutHdl( LINK( this, ImplWheelWindow, ImplScrollHdl ) );
    mpTimer->SetTimeout( mnTimeout );
    mpTimer->Start();

    CaptureMouse();
}

// ------------------------------------------------------------------------

ImplWheelWindow::~ImplWheelWindow()
{
    ImplStop();
    delete mpTimer;
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplStop()
{
    ReleaseMouse();
    mpTimer->Stop();
    Show(FALSE);
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplSetRegion( const Bitmap& rRegionBmp )
{
    Point           aPos( GetPointerPosPixel() );
    const Size      aSize( rRegionBmp.GetSizePixel() );
    Point           aPoint;
    const Rectangle aRect( aPoint, aSize );

    maCenter = maLastMousePos = aPos;
    aPos.X() -= aSize.Width() >> 1;
    aPos.Y() -= aSize.Height() >> 1;

    SetPosSizePixel( aPos, aSize );
    SetWindowRegionPixel( rRegionBmp.CreateRegion( COL_BLACK, aRect ) );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplCreateImageList()
{
    ResMgr* pResMgr = ImplGetResMgr();
    if( pResMgr )
        maImgList.InsertFromHorizontalBitmap
            ( ResId( SV_RESID_BITMAP_SCROLLBMP, *pResMgr ), 6, NULL );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplSetWheelMode( ULONG nWheelMode )
{
    if( nWheelMode != mnWheelMode )
    {
        mnWheelMode = nWheelMode;

        if( WHEELMODE_NONE == mnWheelMode )
        {
            if( IsVisible() )
                Hide();
        }
        else
        {
            if( !IsVisible() )
                Show();

            ImplDrawWheel();
        }
    }
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplDrawWheel()
{
    USHORT nId;

    switch( mnWheelMode )
    {
        case( WHEELMODE_VH ):       nId = 1; break;
        case( WHEELMODE_V    ):     nId = 2; break;
        case( WHEELMODE_H    ):     nId = 3; break;
        case( WHEELMODE_SCROLL_VH ):nId = 4; break;
        case( WHEELMODE_SCROLL_V ): nId = 5; break;
        case( WHEELMODE_SCROLL_H ): nId = 6; break;
        default:                    nId = 0; break;
    }

    if( nId )
        DrawImage( Point(), maImgList.GetImage( nId ) );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplRecalcScrollValues()
{
    if( mnActDist < WHEEL_RADIUS )
    {
        mnActDeltaX = mnActDeltaY = 0L;
        mnTimeout = DEF_TIMEOUT;
    }
    else
    {
        ULONG nCurTime;

        // calc current time
        if( mnMaxWidth )
        {
            const double fExp = ( (double) mnActDist / mnMaxWidth ) * log10( (double) MAX_TIME / MIN_TIME );
            nCurTime = (ULONG) ( MAX_TIME / pow( 10., fExp ) );
        }
        else
            nCurTime = MAX_TIME;

        if( !nCurTime )
            nCurTime = 1UL;

        if( mnRepaintTime <= nCurTime )
            mnTimeout = nCurTime - mnRepaintTime;
        else
        {
            long nMult = mnRepaintTime / nCurTime;

            if( !( mnRepaintTime % nCurTime ) )
                mnTimeout = 0UL;
            else
                mnTimeout = ++nMult * nCurTime - mnRepaintTime;

            double fValX = (double) mnActDeltaX * nMult;
            double fValY = (double) mnActDeltaY * nMult;

            if( fValX > LONG_MAX )
                mnActDeltaX = LONG_MAX;
            else if( fValX < LONG_MIN )
                mnActDeltaX = LONG_MIN;
            else
                mnActDeltaX = (long) fValX;

            if( fValY > LONG_MAX )
                mnActDeltaY = LONG_MAX;
            else if( fValY < LONG_MIN )
                mnActDeltaY = LONG_MIN;
            else
                mnActDeltaY = (long) fValY;
        }
    }
}

// ------------------------------------------------------------------------

PointerStyle ImplWheelWindow::ImplGetMousePointer( long nDistX, long nDistY )
{
    PointerStyle    eStyle;
    const USHORT    nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL      bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL      bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;

    if( bHorz || bVert )
    {
        if( mnActDist < WHEEL_RADIUS )
        {
            if( bHorz && bVert )
                eStyle = POINTER_AUTOSCROLL_NSWE;
            else if( bHorz )
                eStyle = POINTER_AUTOSCROLL_WE;
            else
                eStyle = POINTER_AUTOSCROLL_NS;
        }
        else
        {
            double fAngle = atan2( (double) -nDistY, nDistX ) / F_PI180;

            if( fAngle < 0.0 )
                fAngle += 360.;

            if( bHorz && bVert )
            {
                if( fAngle >= 22.5 && fAngle <= 67.5 )
                    eStyle = POINTER_AUTOSCROLL_NE;
                else if( fAngle >= 67.5 && fAngle <= 112.5 )
                    eStyle = POINTER_AUTOSCROLL_N;
                else if( fAngle >= 112.5 && fAngle <= 157.5 )
                    eStyle = POINTER_AUTOSCROLL_NW;
                else if( fAngle >= 157.5 && fAngle <= 202.5 )
                    eStyle = POINTER_AUTOSCROLL_W;
                else if( fAngle >= 202.5 && fAngle <= 247.5 )
                    eStyle = POINTER_AUTOSCROLL_SW;
                else if( fAngle >= 247.5 && fAngle <= 292.5 )
                    eStyle = POINTER_AUTOSCROLL_S;
                else if( fAngle >= 292.5 && fAngle <= 337.5 )
                    eStyle = POINTER_AUTOSCROLL_SE;
                else
                    eStyle = POINTER_AUTOSCROLL_E;
            }
            else if( bHorz )
            {
                if( fAngle >= 270. || fAngle <= 90. )
                    eStyle = POINTER_AUTOSCROLL_E;
                else
                    eStyle = POINTER_AUTOSCROLL_W;
            }
            else
            {
                if( fAngle >= 0. && fAngle <= 180. )
                    eStyle = POINTER_AUTOSCROLL_N;
                else
                    eStyle = POINTER_AUTOSCROLL_S;
            }
        }
    }
    else
        eStyle = POINTER_ARROW;

    return eStyle;
}

// ------------------------------------------------------------------------

void ImplWheelWindow::Paint( const Rectangle& )
{
    ImplDrawWheel();
}

// ------------------------------------------------------------------------

void ImplWheelWindow::MouseMove( const MouseEvent& rMEvt )
{
    FloatingWindow::MouseMove( rMEvt );

    const Point aMousePos( OutputToScreenPixel( rMEvt.GetPosPixel() ) );
    const long  nDistX = aMousePos.X() - maCenter.X();
    const long  nDistY = aMousePos.Y() - maCenter.Y();

    mnActDist = (ULONG) hypot( (double) nDistX, nDistY );

    const PointerStyle  eActStyle = ImplGetMousePointer( nDistX, nDistY );
    const USHORT        nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL          bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL          bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;
    const BOOL          bOuter = mnActDist > WHEEL_RADIUS;

    if( bOuter && ( maLastMousePos != aMousePos ) )
    {
        switch( eActStyle )
        {
            case( POINTER_AUTOSCROLL_N ):   mnActDeltaX = +0L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_S ):   mnActDeltaX = +0L, mnActDeltaY = -1L; break;
            case( POINTER_AUTOSCROLL_W ):   mnActDeltaX = +1L, mnActDeltaY = +0L; break;
            case( POINTER_AUTOSCROLL_E ):   mnActDeltaX = -1L, mnActDeltaY = +0L; break;
            case( POINTER_AUTOSCROLL_NW ):  mnActDeltaX = +1L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_NE ):  mnActDeltaX = -1L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_SW ):  mnActDeltaX = +1L, mnActDeltaY = -1L; break;
            case( POINTER_AUTOSCROLL_SE ):  mnActDeltaX = -1L, mnActDeltaY = -1L; break;

            default:
            break;
        }
    }

    ImplRecalcScrollValues();
    maLastMousePos = aMousePos;
    SetPointer( eActStyle );

    if( bHorz && bVert )
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_VH : WHEELMODE_VH );
    else if( bHorz )
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_H : WHEELMODE_H );
    else
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_V : WHEELMODE_V );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::MouseButtonUp( const MouseEvent& rMEvt )
{
    if( mnActDist > WHEEL_RADIUS )
        GetParent()->EndAutoScroll();
    else
        FloatingWindow::MouseButtonUp( rMEvt );
}

// ------------------------------------------------------------------------

IMPL_LINK( ImplWheelWindow, ImplScrollHdl, Timer*, EMPTYARG )
{
    if ( mnActDeltaX || mnActDeltaY )
    {
        Window*             pWindow = GetParent();
        const Point         aMousePos( pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() ) );
        Point               aCmdMousePos( pWindow->ImplFrameToOutput( aMousePos ) );
        CommandScrollData   aScrollData( mnActDeltaX, mnActDeltaY );
        CommandEvent        aCEvt( aCmdMousePos, COMMAND_AUTOSCROLL, TRUE, &aScrollData );
        NotifyEvent         aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );

        if ( !ImplCallPreNotify( aNCmdEvt ) )
        {
            const ULONG nTime = Time::GetSystemTicks();
            ImplDelData aDel( this );
            pWindow->Command( aCEvt );
            if( aDel.IsDead() )
                return 0;
            mnRepaintTime = Max( Time::GetSystemTicks() - nTime, 1UL );
            ImplRecalcScrollValues();
        }
    }

    if ( mnTimeout != mpTimer->GetTimeout() )
        mpTimer->SetTimeout( mnTimeout );
    mpTimer->Start();

    return 0L;
}
<|endoftext|>