<commit_before>// Filename: windowsRegistry.cxx
// Created by:  drose (06Aug01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "windowsRegistry.h"
#include "config_express.h"
#include "textEncoder.h"

#ifdef WIN32_VC
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::set_string_value
//       Access: Published, Static
//  Description: Sets the registry key to the indicated value as a
//               string.  The supplied string value is automatically
//               converted from whatever encoding is set by
//               TextEncoder::set_default_encoding() and written as a
//               Unicode string.  The registry key must already exist
//               prior to calling this function.
////////////////////////////////////////////////////////////////////
bool WindowsRegistry::
set_string_value(const string &key, const string &name, const string &value,
        WindowsRegistry::RegLevel rl)
{
  TextEncoder encoder;
  wstring wvalue = encoder.decode_text(value);

  bool okflag = true;

  // Now convert the string to Windows' idea of the correct wide-char
  // encoding, so we can store it in the registry.  This might well be
  // the same string we just decoded from, but it might not.

  // Windows likes to have a null character trailing the string (even
  // though we also pass a length).
  wvalue += (wchar_t)0;
  int mb_result_len =
    WideCharToMultiByte(CP_ACP, 0,
                        wvalue.data(), wvalue.length(),
                        NULL, 0,
                        NULL, NULL);
  if (mb_result_len == 0) {
    express_cat.error()
      << "Unable to convert '" << value
      << "' from Unicode to MultiByte form.\n";
    return false;
  }

  char *mb_result = (char *)alloca(mb_result_len);
  WideCharToMultiByte(CP_ACP, 0,
                      wvalue.data(), wvalue.length(),
                      mb_result, mb_result_len,
                      NULL, NULL);

  if (express_cat.is_debug()) {
    express_cat.debug()
      << "Converted '" << value << "' to '" << mb_result
      << "' for storing in registry.\n";
  }

  return do_set(key, name, REG_SZ, mb_result, mb_result_len, rl);
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::set_int_value
//       Access: Published, Static
//  Description: Sets the registry key to the indicated value as an
//               integer.  The registry key must already exist prior
//               to calling this function.
////////////////////////////////////////////////////////////////////
bool WindowsRegistry::
set_int_value(const string &key, const string &name, int value,
        WindowsRegistry::RegLevel rl)
{
  DWORD dw = value;
  return do_set(key, name, REG_DWORD, &dw, sizeof(dw), rl);
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::get_key_type
//       Access: Published, Static
//  Description: Returns the type of the indicated key, or T_none if
//               the key is not known or is some unsupported type.
////////////////////////////////////////////////////////////////////
WindowsRegistry::Type WindowsRegistry::
get_key_type(const string &key, const string &name,
        WindowsRegistry::RegLevel rl)
{
  int data_type;
  string data;
  if (!do_get(key, name, data_type, data, rl)) {
    return T_none;
  }

  switch (data_type) {
  case REG_SZ:
    return T_string;

  case REG_DWORD:
    return T_int;

  default:
    return T_none;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::get_string_value
//       Access: Published, Static
//  Description: Returns the value associated with the indicated
//               registry key, assuming it is a string value.  The
//               string value is automatically encoded using
//               TextEncoder::get_default_encoding().  If the key is
//               not defined or is not a string type value,
//               default_value is returned instead.
////////////////////////////////////////////////////////////////////
string WindowsRegistry::
get_string_value(const string &key, const string &name,
                 const string &default_value,
                 WindowsRegistry::RegLevel rl)
{
  int data_type;
  string data;
  if (!do_get(key, name, data_type, data, rl)) {
    return default_value;
  }

  if (data_type != REG_SZ) {
    express_cat.warning()
      << "Registry key " << key << " does not contain a string value.\n";
    return default_value;
  }

  // Now we have to decode the MultiByte string to Unicode, and re-encode
  // it according to our own encoding.

  if (data.empty()) {
    return data;
  }

  int wide_result_len =
    MultiByteToWideChar(CP_ACP, 0,
                        data.data(), data.length(),
                        NULL, 0);
  if (wide_result_len == 0) {
    express_cat.error()
      << "Unable to convert '" << data
      << "' from MultiByte to Unicode form.\n";
    return data;
  }

  wchar_t *wide_result = (wchar_t *)alloca(wide_result_len * sizeof(wchar_t));
  MultiByteToWideChar(CP_ACP, 0,
                      data.data(), data.length(),
                      wide_result, wide_result_len);

  wstring wdata(wide_result, wide_result_len);

  TextEncoder encoder;
  string result = encoder.encode_wtext(wdata);

  if (express_cat.is_debug()) {
    express_cat.debug()
      << "Converted '" << data << "' from registry to '" << result << "'\n";
  }

  return result;
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::get_int_value
//       Access: Published, Static
//  Description: Returns the value associated with the indicated
//               registry key, assuming it is an integer value.  If
//               the key is not defined or is not an integer type
//               value, default_value is returned instead.
////////////////////////////////////////////////////////////////////
int WindowsRegistry::
get_int_value(const string &key, const string &name, int default_value,
        WindowsRegistry::RegLevel rl)
{
  int data_type;
  string data;
  if (!do_get(key, name, data_type, data, rl)) {
    return default_value;
  }

  if (data_type != REG_DWORD) {
    express_cat.warning()
      << "Registry key " << key << " does not contain an integer value.\n";
    return default_value;
  }

  // Now we have a DWORD encoded in a string.
  nassertr(data.length() == sizeof(DWORD), default_value);
  DWORD dw = *(DWORD *)data.data();
  return dw;
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::do_set
//       Access: Private, Static
//  Description: The internal function to actually make all of the
//               appropriate windows calls to set the registry value.
////////////////////////////////////////////////////////////////////
bool WindowsRegistry::
do_set(const string &key, const string &name,
       int data_type, const void *data, int data_length,
       const WindowsRegistry::RegLevel rl)
{
  HKEY hkey, regkey = HKEY_LOCAL_MACHINE;
  LONG error;

  if (rl == rl_user)    // switch to user local settings
      regkey = HKEY_CURRENT_USER;

  error =
    RegOpenKeyEx(regkey, key.c_str(), 0, KEY_SET_VALUE, &hkey);
  if (error != ERROR_SUCCESS) {
    express_cat.error()
      << "Unable to open registry key " << key
      << ": " << format_message(error) << "\n";
    return false;
  }

  bool okflag = true;

  error =
    RegSetValueEx(hkey, name.c_str(), 0, data_type,
                  (CONST BYTE *)data, data_length);
  if (error != ERROR_SUCCESS) {
    express_cat.error()
      << "Unable to set registry key " << key << " name " << name
      << ": " << format_message(error) << "\n";
    okflag = false;
  }

  error = RegCloseKey(hkey);
  if (error != ERROR_SUCCESS) {
    express_cat.warning()
      << "Unable to close opened registry key " << key
      << ": " << format_message(error) << "\n";
  }

  return okflag;
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::do_get
//       Access: Private, Static
//  Description: The internal function to actually make all of the
//               appropriate windows calls to retrieve the registry
//               value.
////////////////////////////////////////////////////////////////////
bool WindowsRegistry::
do_get(const string &key, const string &name, int &data_type, string &data,
       const WindowsRegistry::RegLevel rl)
{
  HKEY hkey, regkey = HKEY_LOCAL_MACHINE;
  LONG error;

  if (rl == rl_user)    // switch to user local settings
      regkey = HKEY_CURRENT_USER;

  error =
    RegOpenKeyEx(regkey, key.c_str(), 0, KEY_QUERY_VALUE, &hkey);
  if (error != ERROR_SUCCESS) {
    express_cat.debug()
      << "Unable to open registry key " << key
      << ": " << format_message(error) << "\n";
    return false;
  }

  bool okflag = true;

  // We start with a 1K buffer; presumably that will be big enough
  // most of the time.
  static const size_t init_buffer_size = 1024;
  char init_buffer[init_buffer_size];
  DWORD buffer_size = init_buffer_size;
  DWORD dw_data_type;

  error =
    RegQueryValueEx(hkey, name.c_str(), 0, &dw_data_type,
                    (BYTE *)init_buffer, &buffer_size);
  if (error == ERROR_SUCCESS) {
    data_type = dw_data_type;
    if (data_type == REG_SZ ||
        data_type == REG_MULTI_SZ ||
        data_type == REG_EXPAND_SZ) {
      // Eliminate the trailing null character.
      buffer_size--;
    }
    data = string(init_buffer, buffer_size);

  } else if (error == ERROR_MORE_DATA) {
    // Huh, 1K wasn't big enough.  Ok, get a bigger buffer.

    // If we were querying HKEY_PERFORMANCE_DATA, we'd have to keep
    // guessing bigger and bigger until we got it.  Since we're
    // querying static data for now, we can just use the size Windows
    // tells us.
    char *new_buffer = (char *)PANDA_MALLOC_ARRAY(buffer_size);
    error =
      RegQueryValueEx(hkey, name.c_str(), 0, &dw_data_type,
                      (BYTE *)new_buffer, &buffer_size);
    if (error == ERROR_SUCCESS) {
      data_type = dw_data_type;
      if (data_type == REG_SZ ||
          data_type == REG_MULTI_SZ ||
          data_type == REG_EXPAND_SZ) {
        // Eliminate the trailing null character.
        buffer_size--;
      }
      data = string(new_buffer, buffer_size);
    }
    PANDA_FREE_ARRAY(new_buffer);
  }

  if (error != ERROR_SUCCESS) {
    express_cat.debug()
      << "Unable to get registry value " << name
      << ": " << format_message(error) << "\n";
    okflag = false;
  }

  error = RegCloseKey(hkey);
  if (error != ERROR_SUCCESS) {
    express_cat.warning()
      << "Unable to close opened registry key " << key
      << ": " << format_message(error) << "\n";
  }

  if (okflag) {
    if (data_type == REG_EXPAND_SZ) {
      // Expand the string.
      DWORD destSize=ExpandEnvironmentStrings(data.c_str(), 0, 0);
      char *dest = (char *)PANDA_MALLOC_ARRAY(destSize);
      ExpandEnvironmentStrings(data.c_str(), dest, destSize);
      data = dest;
      PANDA_FREE_ARRAY(dest);
      data_type = REG_SZ;
    }
  }

  return okflag;
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::format_message
//       Access: Private, Static
//  Description: Returns the Windows error message associated with the
//               given error code.
////////////////////////////////////////////////////////////////////
string WindowsRegistry::
format_message(int error_code) {
  PVOID buffer;
  DWORD length =
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                  NULL, error_code, 0, (LPTSTR)&buffer, 0, NULL);
  if (length == 0) {
    return "Unknown error message";
  }

  const char *text = (const char *)buffer;

  // Strip off \n's and \r's trailing the string.
  while (length > 0 &&
         (text[length - 1] == '\r' || text[length - 1] == '\n')) {
    length--;
  }

  string result((const char *)text, length);
  LocalFree(buffer);
  return result;
}

#endif  // WIN32_VC
<commit_msg>don't decrement zero-length REG_*SZ strings passed back from the registry<commit_after>// Filename: windowsRegistry.cxx
// Created by:  drose (06Aug01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "windowsRegistry.h"
#include "config_express.h"
#include "textEncoder.h"

#ifdef WIN32_VC
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::set_string_value
//       Access: Published, Static
//  Description: Sets the registry key to the indicated value as a
//               string.  The supplied string value is automatically
//               converted from whatever encoding is set by
//               TextEncoder::set_default_encoding() and written as a
//               Unicode string.  The registry key must already exist
//               prior to calling this function.
////////////////////////////////////////////////////////////////////
bool WindowsRegistry::
set_string_value(const string &key, const string &name, const string &value,
        WindowsRegistry::RegLevel rl)
{
  TextEncoder encoder;
  wstring wvalue = encoder.decode_text(value);

  bool okflag = true;

  // Now convert the string to Windows' idea of the correct wide-char
  // encoding, so we can store it in the registry.  This might well be
  // the same string we just decoded from, but it might not.

  // Windows likes to have a null character trailing the string (even
  // though we also pass a length).
  wvalue += (wchar_t)0;
  int mb_result_len =
    WideCharToMultiByte(CP_ACP, 0,
                        wvalue.data(), wvalue.length(),
                        NULL, 0,
                        NULL, NULL);
  if (mb_result_len == 0) {
    express_cat.error()
      << "Unable to convert '" << value
      << "' from Unicode to MultiByte form.\n";
    return false;
  }

  char *mb_result = (char *)alloca(mb_result_len);
  WideCharToMultiByte(CP_ACP, 0,
                      wvalue.data(), wvalue.length(),
                      mb_result, mb_result_len,
                      NULL, NULL);

  if (express_cat.is_debug()) {
    express_cat.debug()
      << "Converted '" << value << "' to '" << mb_result
      << "' for storing in registry.\n";
  }

  return do_set(key, name, REG_SZ, mb_result, mb_result_len, rl);
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::set_int_value
//       Access: Published, Static
//  Description: Sets the registry key to the indicated value as an
//               integer.  The registry key must already exist prior
//               to calling this function.
////////////////////////////////////////////////////////////////////
bool WindowsRegistry::
set_int_value(const string &key, const string &name, int value,
        WindowsRegistry::RegLevel rl)
{
  DWORD dw = value;
  return do_set(key, name, REG_DWORD, &dw, sizeof(dw), rl);
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::get_key_type
//       Access: Published, Static
//  Description: Returns the type of the indicated key, or T_none if
//               the key is not known or is some unsupported type.
////////////////////////////////////////////////////////////////////
WindowsRegistry::Type WindowsRegistry::
get_key_type(const string &key, const string &name,
        WindowsRegistry::RegLevel rl)
{
  int data_type;
  string data;
  if (!do_get(key, name, data_type, data, rl)) {
    return T_none;
  }

  switch (data_type) {
  case REG_SZ:
    return T_string;

  case REG_DWORD:
    return T_int;

  default:
    return T_none;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::get_string_value
//       Access: Published, Static
//  Description: Returns the value associated with the indicated
//               registry key, assuming it is a string value.  The
//               string value is automatically encoded using
//               TextEncoder::get_default_encoding().  If the key is
//               not defined or is not a string type value,
//               default_value is returned instead.
////////////////////////////////////////////////////////////////////
string WindowsRegistry::
get_string_value(const string &key, const string &name,
                 const string &default_value,
                 WindowsRegistry::RegLevel rl)
{
  int data_type;
  string data;
  if (!do_get(key, name, data_type, data, rl)) {
    return default_value;
  }

  if (data_type != REG_SZ) {
    express_cat.warning()
      << "Registry key " << key << " does not contain a string value.\n";
    return default_value;
  }

  // Now we have to decode the MultiByte string to Unicode, and re-encode
  // it according to our own encoding.

  if (data.empty()) {
    return data;
  }

  int wide_result_len =
    MultiByteToWideChar(CP_ACP, 0,
                        data.data(), data.length(),
                        NULL, 0);
  if (wide_result_len == 0) {
    express_cat.error()
      << "Unable to convert '" << data
      << "' from MultiByte to Unicode form.\n";
    return data;
  }

  wchar_t *wide_result = (wchar_t *)alloca(wide_result_len * sizeof(wchar_t));
  MultiByteToWideChar(CP_ACP, 0,
                      data.data(), data.length(),
                      wide_result, wide_result_len);

  wstring wdata(wide_result, wide_result_len);

  TextEncoder encoder;
  string result = encoder.encode_wtext(wdata);

  if (express_cat.is_debug()) {
    express_cat.debug()
      << "Converted '" << data << "' from registry to '" << result << "'\n";
  }

  return result;
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::get_int_value
//       Access: Published, Static
//  Description: Returns the value associated with the indicated
//               registry key, assuming it is an integer value.  If
//               the key is not defined or is not an integer type
//               value, default_value is returned instead.
////////////////////////////////////////////////////////////////////
int WindowsRegistry::
get_int_value(const string &key, const string &name, int default_value,
        WindowsRegistry::RegLevel rl)
{
  int data_type;
  string data;
  if (!do_get(key, name, data_type, data, rl)) {
    return default_value;
  }

  if (data_type != REG_DWORD) {
    express_cat.warning()
      << "Registry key " << key << " does not contain an integer value.\n";
    return default_value;
  }

  // Now we have a DWORD encoded in a string.
  nassertr(data.length() == sizeof(DWORD), default_value);
  DWORD dw = *(DWORD *)data.data();
  return dw;
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::do_set
//       Access: Private, Static
//  Description: The internal function to actually make all of the
//               appropriate windows calls to set the registry value.
////////////////////////////////////////////////////////////////////
bool WindowsRegistry::
do_set(const string &key, const string &name,
       int data_type, const void *data, int data_length,
       const WindowsRegistry::RegLevel rl)
{
  HKEY hkey, regkey = HKEY_LOCAL_MACHINE;
  LONG error;

  if (rl == rl_user)    // switch to user local settings
      regkey = HKEY_CURRENT_USER;

  error =
    RegOpenKeyEx(regkey, key.c_str(), 0, KEY_SET_VALUE, &hkey);
  if (error != ERROR_SUCCESS) {
    express_cat.error()
      << "Unable to open registry key " << key
      << ": " << format_message(error) << "\n";
    return false;
  }

  bool okflag = true;

  error =
    RegSetValueEx(hkey, name.c_str(), 0, data_type,
                  (CONST BYTE *)data, data_length);
  if (error != ERROR_SUCCESS) {
    express_cat.error()
      << "Unable to set registry key " << key << " name " << name
      << ": " << format_message(error) << "\n";
    okflag = false;
  }

  error = RegCloseKey(hkey);
  if (error != ERROR_SUCCESS) {
    express_cat.warning()
      << "Unable to close opened registry key " << key
      << ": " << format_message(error) << "\n";
  }

  return okflag;
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::do_get
//       Access: Private, Static
//  Description: The internal function to actually make all of the
//               appropriate windows calls to retrieve the registry
//               value.
////////////////////////////////////////////////////////////////////
bool WindowsRegistry::
do_get(const string &key, const string &name, int &data_type, string &data,
       const WindowsRegistry::RegLevel rl)
{
  HKEY hkey, regkey = HKEY_LOCAL_MACHINE;
  LONG error;

  if (rl == rl_user)    // switch to user local settings
      regkey = HKEY_CURRENT_USER;

  error =
    RegOpenKeyEx(regkey, key.c_str(), 0, KEY_QUERY_VALUE, &hkey);
  if (error != ERROR_SUCCESS) {
    express_cat.debug()
      << "Unable to open registry key " << key
      << ": " << format_message(error) << "\n";
    return false;
  }

  bool okflag = true;

  // We start with a 1K buffer; presumably that will be big enough
  // most of the time.
  static const size_t init_buffer_size = 1024;
  char init_buffer[init_buffer_size];
  DWORD buffer_size = init_buffer_size;
  DWORD dw_data_type;

  error =
    RegQueryValueEx(hkey, name.c_str(), 0, &dw_data_type,
                    (BYTE *)init_buffer, &buffer_size);
  if (error == ERROR_SUCCESS) {
    data_type = dw_data_type;
    if (data_type == REG_SZ ||
        data_type == REG_MULTI_SZ ||
        data_type == REG_EXPAND_SZ) {
      // Eliminate the trailing null character for non-zero lengths.
      if (buffer_size > 0)              // if zero, leave it
        buffer_size--;
    }
    data = string(init_buffer, buffer_size);

  } else if (error == ERROR_MORE_DATA) {
    // Huh, 1K wasn't big enough.  Ok, get a bigger buffer.

    // If we were querying HKEY_PERFORMANCE_DATA, we'd have to keep
    // guessing bigger and bigger until we got it.  Since we're
    // querying static data for now, we can just use the size Windows
    // tells us.
    char *new_buffer = (char *)PANDA_MALLOC_ARRAY(buffer_size);
    error =
      RegQueryValueEx(hkey, name.c_str(), 0, &dw_data_type,
                      (BYTE *)new_buffer, &buffer_size);
    if (error == ERROR_SUCCESS) {
      data_type = dw_data_type;
      if (data_type == REG_SZ ||
          data_type == REG_MULTI_SZ ||
          data_type == REG_EXPAND_SZ) {
        // Eliminate the trailing null character for non-zero lengths.
        if (buffer_size > 0)            // if zero, leave it
          buffer_size--;
      }
      data = string(new_buffer, buffer_size);
    }
    PANDA_FREE_ARRAY(new_buffer);
  }

  if (error != ERROR_SUCCESS) {
    express_cat.debug()
      << "Unable to get registry value " << name
      << ": " << format_message(error) << "\n";
    okflag = false;
  }

  error = RegCloseKey(hkey);
  if (error != ERROR_SUCCESS) {
    express_cat.warning()
      << "Unable to close opened registry key " << key
      << ": " << format_message(error) << "\n";
  }

  if (okflag) {
    if (data_type == REG_EXPAND_SZ) {
      // Expand the string.
      DWORD destSize=ExpandEnvironmentStrings(data.c_str(), 0, 0);
      char *dest = (char *)PANDA_MALLOC_ARRAY(destSize);
      ExpandEnvironmentStrings(data.c_str(), dest, destSize);
      data = dest;
      PANDA_FREE_ARRAY(dest);
      data_type = REG_SZ;
    }
  }

  return okflag;
}

////////////////////////////////////////////////////////////////////
//     Function: WindowsRegistry::format_message
//       Access: Private, Static
//  Description: Returns the Windows error message associated with the
//               given error code.
////////////////////////////////////////////////////////////////////
string WindowsRegistry::
format_message(int error_code) {
  PVOID buffer;
  DWORD length =
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                  NULL, error_code, 0, (LPTSTR)&buffer, 0, NULL);
  if (length == 0) {
    return "Unknown error message";
  }

  const char *text = (const char *)buffer;

  // Strip off \n's and \r's trailing the string.
  while (length > 0 &&
         (text[length - 1] == '\r' || text[length - 1] == '\n')) {
    length--;
  }

  string result((const char *)text, length);
  LocalFree(buffer);
  return result;
}

#endif  // WIN32_VC
<|endoftext|>


<commit_before>/* gk_WellKnownCpuBindings.cpp	Mon Oct 31 2016 13:22:28 tmm */

/*

Module:  gk_WellKnownCpuBindings.cpp

Function:
	The table of well-known CPU-instance to platform bindings.

Version:
	V0.3.0	Mon Oct 31 2016 13:22:28 tmm	Edit level 2

Copyright notice:
	This file copyright (C) 2016 by

		MCCI Corporation
		3520 Krums Corners Road
		Ithaca, NY  14850

	An unpublished work.  All rights reserved.

	This file is proprietary information, and may not be disclosed or
	copied without the prior permission of MCCI Corporation.

Author:
	Terry Moore, MCCI Corporation	October 2016

Revision history:
   0.1.0  Mon Oct 17 2016 03:38:02  tmm
	Module created.

*/

#include "Catena4410.h"
#include "catena_platforms.h"

/****************************************************************************\
|
|		Manifest constants & typedefs.
|
|	This is strictly for private types and constants which will not
|	be exported.
|
\****************************************************************************/

/****************************************************************************\
|
|	Read-only data.
|
|	If program is to be ROM-able, these must all be tagged read-only
|	using the ROM storage class; they may be global.
|
\****************************************************************************/

/*
function _cpuid {
        echo "$1" |
        sed -e 's/^/0x/' -e 's/-/, 0x/g' |
        nawk '{
                $1 = "        { CpuID:  { " $1;
                $8 = $8 "\n\t\t   ";
                $16 = $16 " },";
                print }' ;
}
*/

const CATENA_CPUID_TO_PLATFORM CatenaSamd21::vCpuIdToPlatform[] =
    {
	{ CpuID:  { 0x08, 0x3b, 0xaf, 0x31, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x1b, 0x1f, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_pond,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x00 },
	  OperatingFlagsClear:  0,
	  OperatingFlagsSet:    /* CatenaSamd21::fUnattended | */ 0,
	},

	{ CpuID:  { 0xea, 0xa3, 0x7e, 0x87, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x3d, 0x21, 0x13, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x01 },
	},

	{ CpuID:  { 0xb0, 0xa9, 0x2f, 0x58, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x41, 0x23, 0x12, 0xff },
	  pPlatform: &gkPlatformCatena4410_gh,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x02 },
	},

        { CpuID:  { 0xcf, 0x1b, 0x20, 0xa5, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x2e, 0x06, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x03 },
	},

        { CpuID:  { 0xa3, 0xad, 0xd0, 0x3a, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x1e, 0x13, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x04 },
	},

        { CpuID:  { 0xda, 0x0e, 0x42, 0x5a, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x33, 0x2b, 0x12, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x05},
        },

        { CpuID:  { 0xc4, 0x8b, 0x81, 0xf7, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x3c, 0x28, 0x13, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x06},
	},

        { CpuID:  { 0x66, 0x52, 0x24, 0x98, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x1b, 0x08, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x07},
	},

        { CpuID:  { 0x34, 0xd8, 0xa0, 0xf7, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x18, 0x2d, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x08},
	},

        { CpuID:  { 0x67, 0x5c, 0xc2, 0xff, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x21, 0x32, 0x13, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x09},
	},

    };

const size_t CatenaSamd21::nvCpuIdToPlatform =
		MCCIADK_LENOF(CatenaSamd21::vCpuIdToPlatform);

/****************************************************************************\
|
|	VARIABLES:
|
|	If program is to be ROM-able, these must be initialized
|	using the BSS keyword.  (This allows for compilers that require
|	every variable to have an initializer.)  Note that only those
|	variables owned by this module should be declared here, using the BSS
|	keyword; this allows for linkers that dislike multiple declarations
|	of objects.
|
\****************************************************************************/

<commit_msg>Add more CPUs<commit_after>/* gk_WellKnownCpuBindings.cpp	Mon Oct 31 2016 13:22:28 tmm */

/*

Module:  gk_WellKnownCpuBindings.cpp

Function:
	The table of well-known CPU-instance to platform bindings.

Version:
	V0.3.0	Mon Oct 31 2016 13:22:28 tmm	Edit level 2

Copyright notice:
	This file copyright (C) 2016 by

		MCCI Corporation
		3520 Krums Corners Road
		Ithaca, NY  14850

	An unpublished work.  All rights reserved.

	This file is proprietary information, and may not be disclosed or
	copied without the prior permission of MCCI Corporation.

Author:
	Terry Moore, MCCI Corporation	October 2016

Revision history:
   0.1.0  Mon Oct 17 2016 03:38:02  tmm
	Module created.

*/

#include "Catena4410.h"
#include "catena_platforms.h"

/****************************************************************************\
|
|		Manifest constants & typedefs.
|
|	This is strictly for private types and constants which will not
|	be exported.
|
\****************************************************************************/

/****************************************************************************\
|
|	Read-only data.
|
|	If program is to be ROM-able, these must all be tagged read-only
|	using the ROM storage class; they may be global.
|
\****************************************************************************/

/*
function _cpuid {
        echo "$1" |
        sed -e 's/^/0x/' -e 's/-/, 0x/g' |
        nawk '{
                $1 = "        { CpuID:  { " $1;
                $8 = $8 "\n\t\t   ";
                $16 = $16 " },";
                print }' ;
}
*/

const CATENA_CPUID_TO_PLATFORM CatenaSamd21::vCpuIdToPlatform[] =
    {
	{ CpuID:  { 0x08, 0x3b, 0xaf, 0x31, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x1b, 0x1f, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_pond,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x00 },
	  OperatingFlagsClear:  0,
	  OperatingFlagsSet:    /* CatenaSamd21::fUnattended | */ 0,
	},

	{ CpuID:  { 0xea, 0xa3, 0x7e, 0x87, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x3d, 0x21, 0x13, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x01 },
	},

	{ CpuID:  { 0xb0, 0xa9, 0x2f, 0x58, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x41, 0x23, 0x12, 0xff },
	  pPlatform: &gkPlatformCatena4410_gh,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x02 },
	},

        { CpuID:  { 0xcf, 0x1b, 0x20, 0xa5, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x2e, 0x06, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x03 },
	},

        { CpuID:  { 0xa3, 0xad, 0xd0, 0x3a, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x1e, 0x13, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x04 },
	},

        { CpuID:  { 0xda, 0x0e, 0x42, 0x5a, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x33, 0x2b, 0x12, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x05},
        },

        { CpuID:  { 0xc4, 0x8b, 0x81, 0xf7, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x3c, 0x28, 0x13, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x06},
	},

        { CpuID:  { 0x66, 0x52, 0x24, 0x98, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x1b, 0x08, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x07},
	},

        { CpuID:  { 0x34, 0xd8, 0xa0, 0xf7, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x18, 0x2d, 0x11, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x08},
	},

        { CpuID:  { 0x67, 0x5c, 0xc2, 0xff, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x21, 0x32, 0x13, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x09},
	},

        { CpuID:  { 0x23, 0x47, 0x48, 0xbb, 0x35, 0x50, 0x4d, 0x51,
		    0x20, 0x20, 0x20, 0x33, 0x27, 0x1a, 0x13, 0xff },
	  pPlatform: &gkPlatformCatena4410_anatolian,
	  SysEUI: { 0x00, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x0b},
	},

    };

const size_t CatenaSamd21::nvCpuIdToPlatform =
		MCCIADK_LENOF(CatenaSamd21::vCpuIdToPlatform);

/****************************************************************************\
|
|	VARIABLES:
|
|	If program is to be ROM-able, these must be initialized
|	using the BSS keyword.  (This allows for compilers that require
|	every variable to have an initializer.)  Note that only those
|	variables owned by this module should be declared here, using the BSS
|	keyword; this allows for linkers that dislike multiple declarations
|	of objects.
|
\****************************************************************************/

<|endoftext|>


<commit_before>#include "material/refraction.h"
#include "scene/hitable.h"

//#pragma optimize( "", off)

namespace AT_NAME
{
	AT_DEVICE_MTRL_API real refraction::pdf(
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v)
	{
		AT_ASSERT(false);

		auto ret = real(1);
		return ret;
	}

	AT_DEVICE_MTRL_API real refraction::pdf(
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v) const
	{
		return pdf(&m_param, normal, wi, wo, u, v);
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::sampleDirection(
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		real u, real v,
		aten::sampler* sampler)
	{
		AT_ASSERT(false);

		aten::vec3 in = -wi;
		aten::vec3 nml = normal;

		bool into = (dot(in, normal) > real(0));

		if (!into) {
			nml = -nml;
		}

		auto reflect = wi - 2 * dot(nml, wi) * nml;
		reflect = normalize(reflect);

		return std::move(reflect);
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::sampleDirection(
		const aten::ray& ray,
		const aten::vec3& normal,
		real u, real v,
		aten::sampler* sampler) const
	{
		return std::move(sampleDirection(&m_param, normal, ray.dir, u, v, sampler));
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::bsdf(
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v)
	{
		AT_ASSERT(false);

		aten::vec3 albedo = param->baseColor;
		albedo *= sampleTexture(
			param->albedoMap,
			u, v,
			real(1));

		return std::move(albedo);
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::bsdf(
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v,
		const aten::vec3& externalAlbedo)
	{
		AT_ASSERT(false);

		aten::vec3 albedo = param->baseColor;
		albedo *= externalAlbedo;

		return std::move(albedo);
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::bsdf(
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v) const
	{
		return std::move(bsdf(&m_param, normal, wi, wo, u, v));
	}

	MaterialSampling refraction::sample(
		const aten::ray& ray,
		const aten::vec3& normal,
		const aten::vec3& orgnormal,
		aten::sampler* sampler,
		real u, real v,
		bool isLightPath/*= false*/) const
	{
		MaterialSampling ret;

		sample(
			&ret,
			&m_param,
			normal,
			ray.dir,
			orgnormal,
			sampler,
			u, v,
			isLightPath);

		return std::move(ret);
	}

	AT_DEVICE_MTRL_API void refraction::sample(
		MaterialSampling* result,
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& orgnormal,
		aten::sampler* sampler,
		real u, real v,
		bool isLightPath/*= false*/)
	{
		aten::vec3 in = -wi;
		aten::vec3 nml = normal;

		bool into = (dot(in, normal) > real(0));

		if (!into) {
			nml = -nml;
		}

		auto reflect = wi - 2 * dot(nml, wi) * nml;
		reflect = normalize(reflect);

		real nc = real(1);		// ^̋ܗ.
		real nt = param->ior;	// ̓̋ܗ.
		real nnt = into ? nc / nt : nt / nc;
		real ddn = dot(wi, nml);

		// NOTE
		// cos_t^2 = 1 - sin_t^2
		// sin_t^2 = (nc/nt)^2 * sin_i^2
		//         = (nc/nt)^2 * (1 - cos_i^2)
		// sin_i / sin_t = nt/nc
		//   -> sin_t = (nc/nt) * sin_i
		//            = (nc/nt) * sqrt(1 - cos_i)
		real cos2t = real(1) - nnt * nnt * (real(1) - ddn * ddn);

		aten::vec3 albedo = param->baseColor;

		if (cos2t < real(0)) {
			//AT_PRINTF("Reflection in refraction...\n");

			// S.
			result->pdf = real(1);
			result->bsdf = albedo;
			result->dir = reflect;
			result->fresnel = real(1);

			return;
		}
#if 1
		aten::vec3 refract = wi * nnt - normal * (into ? real(1) : real(-1)) * (ddn * nnt + sqrt(cos2t));
#else
		// NOTE
		// https://www.vcl.jp/~kanazawa/raytracing/?page_id=478

		auto invnnt = 1 / nnt;
		aten::vec3 refract = nnt * (wi - (aten::sqrt(invnnt * invnnt - (1 - ddn * ddn)) - ddn) * nml);
#endif
		refract = normalize(refract);

		// SchlickɂFresnel̔ˌW̋ߎg.
		const real a = nt - nc;
		const real b = nt + nc;
		const real r0 = (a * a) / (b * b);

		const real c = 1 - (into ? -ddn : dot(refract, -nml));

		// ˕̌˂ray.dir̕ɉ^ԊBɋܕ̌˂ɉ^Ԋ.
		const real fresnel = r0 + (1 - r0) * aten::pow(c, 5);

		auto Re = fresnel;
		auto Tr = (1 - Re);

		real r = real(0.5);
		if (sampler) {
			r = sampler->nextSample();
		}

		if (param->isIdealRefraction) {
			result->dir = refract;

			// C̉^ԕˋPx͋ܗ̈قȂ镨̊ԂړƂAܗ̔̓̕ω.
			if (isLightPath) {
				// TODO
				// vmF...
				nnt = into ? nt / nc : nc / nt;
			}
			else {
				nnt = into ? nc / nt : nt / nc;
			}

			real nnt2 = nnt * nnt;

			result->bsdf = nnt2 * Tr * albedo;

			result->fresnel = 0;

			result->subpdf = real(1);
		}
		else {
			auto prob = real(0.25) + real(0.5) * Re;

			if (r < prob) {
				// .
				result->dir = reflect;
				result->bsdf = Re * albedo;
				result->bsdf /= prob;

				result->subpdf = prob;

				result->fresnel = Re;
			}
			else {
				// .
				result->dir = refract;
				// C̉^ԕˋPx͋ܗ̈قȂ镨̊ԂړƂAܗ̔̓̕ω.
				if (isLightPath) {
					// TODO
					// vmF...
					nnt = into ? nt / nc : nc / nt;
				}
				else {
					nnt = into ? nc / nt : nt / nc;
				}

				real nnt2 = nnt * nnt;

				result->bsdf = nnt2 * Tr * albedo;
				result->bsdf /= (1 - prob);

				result->subpdf = (1 - prob);

				result->fresnel = Tr;
			}
		}

		result->pdf = 1;
	}

	refraction::RefractionSampling refraction::check(
		material* mtrl,
		const aten::vec3& in,
		const aten::vec3& normal,
		const aten::vec3& orienting_normal)
	{
		if (!mtrl->isSingular() || !mtrl->isTranslucent()) {
			return std::move(RefractionSampling(false, real(0), real(0)));
		}

		// C˂Ă鑤̂̋̕ܗ.
		real ni = real(1);	// ^

		// ̓̋ܗ.
		real nt = mtrl->ior();

		bool into = (dot(normal, orienting_normal) > real(0));

		auto reflect = in - 2 * dot(normal, in) * normal;
		reflect = normalize(reflect);

		real cos_i = dot(in, normal);
		real nnt = into ? ni / nt : nt / ni;

		// NOTE
		// cos_t^2 = 1 - sin_t^2
		// sin_t^2 = (nc/nt)^2 * sin_i^2 = (nc/nt)^2 * (1 - cos_i^2)
		// sin_i / sin_t = nt/nc -> sin_t = (nc/nt) * sin_i = (nc/nt) * sqrt(1 - cos_i)
		real cos_t_2 = real(1) - (nnt * nnt) * (real(1) - cos_i * cos_i);

		aten::vec3 albedo = mtrl->color();

		if (cos_t_2 < real(0)) {
			return std::move(RefractionSampling(false, real(1), real(0)));
		}

		aten::vec3 n = into ? normal : -normal;
#if 0
		aten::vec3 refract = in * nnt - hitrec.normal * (into ? 1.0 : -1.0) * (cos_i * nnt + sqrt(cos_t_2));
#else
		// NOTE
		// https://www.vcl.jp/~kanazawa/raytracing/?page_id=478

		auto invnnt = 1 / nnt;
		aten::vec3 refract = nnt * (in - (aten::sqrt(invnnt * invnnt - (1 - cos_i * cos_i)) - (-cos_i)) * normal);
#endif
		refract = normalize(refract);

		const auto r0 = ((nt - ni) * (nt - ni)) / ((nt + ni) * (nt + ni));

		const auto c = 1 - (into ? -cos_i : dot(refract, -normal));

		// ˕̌˂ray.dir̕ɉ^ԊBɋܕ̌˂ɉ^Ԋ.
		auto fresnel = r0 + (1 - r0) * aten::pow(c, 5);

		// C̉^ԕˋPx͋ܗ̈قȂ镨̊ԂړƂAܗ̔̓̕ω.
		real nn = nnt * nnt;

		auto Re = fresnel;
		auto Tr = (1 - Re) * nn;

		refraction* refr = static_cast<refraction*>(mtrl);

		if (refr->isIdealRefraction()) {
			return std::move(RefractionSampling(true, real(0), real(1), true));
		}
		else {
			auto prob = 0.25 + 0.5 * Re;
			return std::move(RefractionSampling(true, real(prob), real(1 - prob)));
		}
	}
}
<commit_msg>Modify refraction.<commit_after>#include "material/refraction.h"
#include "scene/hitable.h"

//#pragma optimize( "", off)

namespace AT_NAME
{
	AT_DEVICE_MTRL_API real refraction::pdf(
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v)
	{
		AT_ASSERT(false);

		auto ret = real(1);
		return ret;
	}

	AT_DEVICE_MTRL_API real refraction::pdf(
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v) const
	{
		return pdf(&m_param, normal, wi, wo, u, v);
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::sampleDirection(
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		real u, real v,
		aten::sampler* sampler)
	{
		AT_ASSERT(false);

		aten::vec3 in = -wi;
		aten::vec3 nml = normal;

		bool into = (dot(in, normal) > real(0));

		if (!into) {
			nml = -nml;
		}

		auto reflect = wi - 2 * dot(nml, wi) * nml;
		reflect = normalize(reflect);

		return std::move(reflect);
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::sampleDirection(
		const aten::ray& ray,
		const aten::vec3& normal,
		real u, real v,
		aten::sampler* sampler) const
	{
		return std::move(sampleDirection(&m_param, normal, ray.dir, u, v, sampler));
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::bsdf(
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v)
	{
		AT_ASSERT(false);

		aten::vec3 albedo = param->baseColor;
		albedo *= sampleTexture(
			param->albedoMap,
			u, v,
			real(1));

		return std::move(albedo);
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::bsdf(
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v,
		const aten::vec3& externalAlbedo)
	{
		AT_ASSERT(false);

		aten::vec3 albedo = param->baseColor;
		albedo *= externalAlbedo;

		return std::move(albedo);
	}

	AT_DEVICE_MTRL_API aten::vec3 refraction::bsdf(
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& wo,
		real u, real v) const
	{
		return std::move(bsdf(&m_param, normal, wi, wo, u, v));
	}

	MaterialSampling refraction::sample(
		const aten::ray& ray,
		const aten::vec3& normal,
		const aten::vec3& orgnormal,
		aten::sampler* sampler,
		real u, real v,
		bool isLightPath/*= false*/) const
	{
		MaterialSampling ret;

		sample(
			&ret,
			&m_param,
			normal,
			ray.dir,
			orgnormal,
			sampler,
			u, v,
			isLightPath);

		return std::move(ret);
	}

	AT_DEVICE_MTRL_API void refraction::sample(
		MaterialSampling* result,
		const aten::MaterialParameter* param,
		const aten::vec3& normal,
		const aten::vec3& wi,
		const aten::vec3& orgnormal,
		aten::sampler* sampler,
		real u, real v,
		bool isLightPath/*= false*/)
	{
		aten::vec3 in = -wi;
		aten::vec3 nml = normal;

		bool into = (dot(in, normal) > real(0));

		if (!into) {
			nml = -nml;
		}

		auto reflect = wi - 2 * dot(nml, wi) * nml;
		reflect = normalize(reflect);

		real nc = real(1);		// ^̋ܗ.
		real nt = param->ior;	// ̓̋ܗ.
		real nnt = into ? nc / nt : nt / nc;
		real ddn = dot(wi, nml);

		// NOTE
		// cos_t^2 = 1 - sin_t^2
		// sin_t^2 = (nc/nt)^2 * sin_i^2
		//         = (nc/nt)^2 * (1 - cos_i^2)
		// sin_i / sin_t = nt/nc
		//   -> sin_t = (nc/nt) * sin_i
		//            = (nc/nt) * sqrt(1 - cos_i)
		real cos2t = real(1) - nnt * nnt * (real(1) - ddn * ddn);

		aten::vec3 albedo = param->baseColor;

		if (cos2t < real(0)) {
			//AT_PRINTF("Reflection in refraction...\n");

			// S.
			result->pdf = real(1);
			result->bsdf = albedo;
			result->dir = reflect;
			result->fresnel = real(1);

			return;
		}
#if 0
		aten::vec3 refract = wi * nnt - normal * (into ? real(1) : real(-1)) * (ddn * nnt + sqrt(cos2t));
#elif 0
		// NOTE
		// https://www.vcl.jp/~kanazawa/raytracing/?page_id=478

		auto invnnt = 1 / nnt;
		aten::vec3 refract = nnt * (wi - (aten::sqrt(invnnt * invnnt - (1 - ddn * ddn)) - ddn) * nml);
#else
		// NOTE
		// https://qiita.com/mebiusbox2/items/315e10031d15173f0aa5

		auto d = dot(in, nml);
		auto refract = -nnt * (in - d * nml) - aten::sqrt(real(1) - nnt * nnt * (1 - ddn * ddn)) * nml;
#endif
		refract = normalize(refract);

		// SchlickɂFresnel̔ˌW̋ߎg.
		const real a = nt - nc;
		const real b = nt + nc;
		const real r0 = (a * a) / (b * b);

		const real c = 1 - (into ? -ddn : dot(refract, -nml));

		// ˕̌˂ray.dir̕ɉ^ԊBɋܕ̌˂ɉ^Ԋ.
		const real fresnel = r0 + (1 - r0) * aten::pow(c, 5);

		auto Re = fresnel;
		auto Tr = (1 - Re);

		real r = real(0.5);
		if (sampler) {
			r = sampler->nextSample();
		}

		if (param->isIdealRefraction) {
			result->dir = refract;

			// C̉^ԕˋPx͋ܗ̈قȂ镨̊ԂړƂAܗ̔̓̕ω.
			if (isLightPath) {
				// TODO
				// vmF...
				nnt = into ? nt / nc : nc / nt;
			}
			else {
				nnt = into ? nc / nt : nt / nc;
			}

			real nnt2 = nnt * nnt;

			result->bsdf = nnt2 * Tr * albedo;

			result->fresnel = 0;

			result->subpdf = real(1);
		}
		else {
			auto prob = real(0.25) + real(0.5) * Re;

			if (r < prob) {
				// .
				result->dir = reflect;
				result->bsdf = Re * albedo;
				result->bsdf /= prob;

				result->subpdf = prob;

				result->fresnel = Re;
			}
			else {
				// .
				result->dir = refract;
				// C̉^ԕˋPx͋ܗ̈قȂ镨̊ԂړƂAܗ̔̓̕ω.
				if (isLightPath) {
					// TODO
					// vmF...
					nnt = into ? nt / nc : nc / nt;
				}
				else {
					nnt = into ? nc / nt : nt / nc;
				}

				real nnt2 = nnt * nnt;

				result->bsdf = nnt2 * Tr * albedo;
				result->bsdf /= (1 - prob);

				result->subpdf = (1 - prob);

				result->fresnel = Tr * nnt2;;
			}
		}

		result->pdf = 1;
	}

	refraction::RefractionSampling refraction::check(
		material* mtrl,
		const aten::vec3& in,
		const aten::vec3& normal,
		const aten::vec3& orienting_normal)
	{
		if (!mtrl->isSingular() || !mtrl->isTranslucent()) {
			return std::move(RefractionSampling(false, real(0), real(0)));
		}

		// C˂Ă鑤̂̋̕ܗ.
		real ni = real(1);	// ^

		// ̓̋ܗ.
		real nt = mtrl->ior();

		bool into = (dot(normal, orienting_normal) > real(0));

		auto reflect = in - 2 * dot(normal, in) * normal;
		reflect = normalize(reflect);

		real cos_i = dot(in, normal);
		real nnt = into ? ni / nt : nt / ni;

		// NOTE
		// cos_t^2 = 1 - sin_t^2
		// sin_t^2 = (nc/nt)^2 * sin_i^2 = (nc/nt)^2 * (1 - cos_i^2)
		// sin_i / sin_t = nt/nc -> sin_t = (nc/nt) * sin_i = (nc/nt) * sqrt(1 - cos_i)
		real cos_t_2 = real(1) - (nnt * nnt) * (real(1) - cos_i * cos_i);

		aten::vec3 albedo = mtrl->color();

		if (cos_t_2 < real(0)) {
			return std::move(RefractionSampling(false, real(1), real(0)));
		}

		aten::vec3 n = into ? normal : -normal;
#if 0
		aten::vec3 refract = in * nnt - hitrec.normal * (into ? 1.0 : -1.0) * (cos_i * nnt + sqrt(cos_t_2));
#else
		// NOTE
		// https://www.vcl.jp/~kanazawa/raytracing/?page_id=478

		auto invnnt = 1 / nnt;
		aten::vec3 refract = nnt * (in - (aten::sqrt(invnnt * invnnt - (1 - cos_i * cos_i)) - (-cos_i)) * normal);
#endif
		refract = normalize(refract);

		const auto r0 = ((nt - ni) * (nt - ni)) / ((nt + ni) * (nt + ni));

		const auto c = 1 - (into ? -cos_i : dot(refract, -normal));

		// ˕̌˂ray.dir̕ɉ^ԊBɋܕ̌˂ɉ^Ԋ.
		auto fresnel = r0 + (1 - r0) * aten::pow(c, 5);

		// C̉^ԕˋPx͋ܗ̈قȂ镨̊ԂړƂAܗ̔̓̕ω.
		real nn = nnt * nnt;

		auto Re = fresnel;
		auto Tr = (1 - Re) * nn;

		refraction* refr = static_cast<refraction*>(mtrl);

		if (refr->isIdealRefraction()) {
			return std::move(RefractionSampling(true, real(0), real(1), true));
		}
		else {
			auto prob = 0.25 + 0.5 * Re;
			return std::move(RefractionSampling(true, real(prob), real(1 - prob)));
		}
	}
}
<|endoftext|>


<commit_before>#include "util/StreamLink.hpp"

#include "Application.hpp"
#include "Helpers.hpp"
#include "singletons/Settings.hpp"
#include "widgets/dialogs/QualityPopup.hpp"

#include <QErrorMessage>
#include <QFileInfo>
#include <QProcess>

#include <functional>

namespace chatterino {

namespace {

const char *getBinaryName()
{
#ifdef _WIN32
    return "streamlink.exe";
#else
    return "streamlink";
#endif
}

const char *getDefaultBinaryPath()
{
#ifdef _WIN32
    return "C:\\Program Files (x86)\\Streamlink\\bin\\streamlink.exe";
#else
    return "/usr/bin/streamlink";
#endif
}

QString getStreamlinkProgram()
{
    auto app = getApp();

    if (getSettings()->streamlinkUseCustomPath) {
        return getSettings()->streamlinkPath + "/" + getBinaryName();
    } else {
        return getBinaryName();
    }
}

bool checkStreamlinkPath(const QString &path)
{
    QFileInfo fileinfo(path);

    if (!fileinfo.exists()) {
        return false;
        // throw Exception(fS("Streamlink path ({}) is invalid, file does not
        // exist", path));
    }

    return fileinfo.isExecutable();
}

void showStreamlinkNotFoundError()
{
    static QErrorMessage *msg = new QErrorMessage;

    auto app = getApp();
    if (getSettings()->streamlinkUseCustomPath) {
        msg->showMessage(
            "Unable to find Streamlink executable\nMake sure your custom path "
            "is pointing "
            "to the DIRECTORY where the streamlink executable is located");
    } else {
        msg->showMessage(
            "Unable to find Streamlink executable.\nIf you have Streamlink "
            "installed, you might need to enable the custom path option");
    }
}

QProcess *createStreamlinkProcess()
{
    auto p = new QProcess;
    p->setProgram(getStreamlinkProgram());

    QObject::connect(p, &QProcess::errorOccurred, [=](auto err) {
        if (err == QProcess::FailedToStart) {
            showStreamlinkNotFoundError();
        } else {
            qDebug() << "Error occured: " << err;  //
        }

        p->deleteLater();
    });

    QObject::connect(p,
                     static_cast<void (QProcess::*)(int)>(&QProcess::finished),
                     [=](int res) {
                         p->deleteLater();  //
                     });

    return p;
}

}  // namespace

void getStreamQualities(const QString &channelURL,
                        std::function<void(QStringList)> cb)
{
    auto p = createStreamlinkProcess();

    QObject::connect(
        p, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
        [=](int res) {
            if (res != 0) {
                qDebug() << "Got error code" << res;
                // return;
            }
            QString lastLine = QString(p->readAllStandardOutput());
            lastLine = lastLine.trimmed().split('\n').last().trimmed();
            if (lastLine.startsWith("Available streams: ")) {
                QStringList options;
                QStringList split =
                    lastLine.right(lastLine.length() - 19).split(", ");

                for (int i = split.length() - 1; i >= 0; i--) {
                    QString option = split.at(i);
                    if (option.endsWith(" (worst)")) {
                        options << option.left(option.length() - 8);
                    } else if (option.endsWith(" (best)")) {
                        options << option.left(option.length() - 7);
                    } else {
                        options << option;
                    }
                }

                cb(options);
            }
        });

    p->setArguments({channelURL, "--default-stream=KKona"});

    p->start();
}

void openStreamlink(const QString &channelURL, const QString &quality,
                    QStringList extraArguments)
{
    auto app = getApp();

    QStringList arguments;

    QString additionalOptions = getSettings()->streamlinkOpts.getValue();
    if (!additionalOptions.isEmpty()) {
        arguments << getSettings()->streamlinkOpts;
    }

    arguments.append(extraArguments);

    arguments << channelURL;

    if (!quality.isEmpty()) {
        arguments << quality;
    }

    bool res = QProcess::startDetached(getStreamlinkProgram() + " " +
                                       QString(arguments.join(' ')));

    if (!res) {
        showStreamlinkNotFoundError();
    }
}

void openStreamlinkForChannel(const QString &channel)
{
    auto app = getApp();

    QString channelURL = "twitch.tv/" + channel;

    QString preferredQuality = getSettings()->preferredQuality;
    preferredQuality = preferredQuality.toLower();

    if (preferredQuality == "choose") {
        getStreamQualities(channelURL, [=](QStringList qualityOptions) {
            QualityPopup::showDialog(channel, qualityOptions);
        });

        return;
    }

    QStringList args;

    // Quality converted from Chatterino format to Streamlink format
    QString quality;
    // Streamlink qualities to exclude
    QString exclude;

    if (preferredQuality == "high") {
        exclude = ">720p30";
        quality = "high,best";
    } else if (preferredQuality == "medium") {
        exclude = ">540p30";
        quality = "medium,best";
    } else if (preferredQuality == "low") {
        exclude = ">360p30";
        quality = "low,best";
    } else if (preferredQuality == "audio only") {
        quality = "audio,audio_only";
    } else {
        quality = "best";
    }
    if (!exclude.isEmpty()) {
        args << "--stream-sorting-excludes" << exclude;
    }

    openStreamlink(channelURL, quality, args);
}

}  // namespace chatterino
<commit_msg>minor streamlink quality option fix (#664)<commit_after>#include "util/StreamLink.hpp"

#include "Application.hpp"
#include "Helpers.hpp"
#include "singletons/Settings.hpp"
#include "widgets/dialogs/QualityPopup.hpp"
#include "debug/Log.hpp"

#include <QErrorMessage>
#include <QFileInfo>
#include <QProcess>

#include <functional>

namespace chatterino {

namespace {

const char *getBinaryName()
{
#ifdef _WIN32
    return "streamlink.exe";
#else
    return "streamlink";
#endif
}

const char *getDefaultBinaryPath()
{
#ifdef _WIN32
    return "C:\\Program Files (x86)\\Streamlink\\bin\\streamlink.exe";
#else
    return "/usr/bin/streamlink";
#endif
}

QString getStreamlinkProgram()
{
    auto app = getApp();

    if (getSettings()->streamlinkUseCustomPath) {
        return getSettings()->streamlinkPath + "/" + getBinaryName();
    } else {
        return getBinaryName();
    }
}

bool checkStreamlinkPath(const QString &path)
{
    QFileInfo fileinfo(path);

    if (!fileinfo.exists()) {
        return false;
        // throw Exception(fS("Streamlink path ({}) is invalid, file does not
        // exist", path));
    }

    return fileinfo.isExecutable();
}

void showStreamlinkNotFoundError()
{
    static QErrorMessage *msg = new QErrorMessage;

    auto app = getApp();
    if (getSettings()->streamlinkUseCustomPath) {
        msg->showMessage(
            "Unable to find Streamlink executable\nMake sure your custom path "
            "is pointing "
            "to the DIRECTORY where the streamlink executable is located");
    } else {
        msg->showMessage(
            "Unable to find Streamlink executable.\nIf you have Streamlink "
            "installed, you might need to enable the custom path option");
    }
}

QProcess *createStreamlinkProcess()
{
    auto p = new QProcess;
    p->setProgram(getStreamlinkProgram());

    QObject::connect(p, &QProcess::errorOccurred, [=](auto err) {
        if (err == QProcess::FailedToStart) {
            showStreamlinkNotFoundError();
        } else {
            log("Error occured {}", err);
        }

        p->deleteLater();
    });

    QObject::connect(p,
                     static_cast<void (QProcess::*)(int)>(&QProcess::finished),
                     [=](int res) {
                         p->deleteLater();  //
                     });

    return p;
}

}  // namespace

void getStreamQualities(const QString &channelURL,
                        std::function<void(QStringList)> cb)
{
    auto p = createStreamlinkProcess();

    QObject::connect(
        p, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
        [=](int res) {
            if (res != 0) {
                log("Got error code {}", res);
                // return;
            }
            QString lastLine = QString(p->readAllStandardOutput());
            lastLine = lastLine.trimmed().split('\n').last().trimmed();
            if (lastLine.startsWith("Available streams: ")) {
                QStringList options;
                QStringList split =
                    lastLine.right(lastLine.length() - 19).split(", ");

                for (int i = split.length() - 1; i >= 0; i--) {
                    QString option = split.at(i);
                    if (option == "best)") {
                        // As it turns out, sometimes, one quality option can
                        // be the best and worst quality at the same time.
                        // Since we start loop from the end, we can check
                        // that and act accordingly
                        option = split.at(--i);
                        // "900p60 (worst"
                        options << option.left(option.length() - 7);
                    } else if (option.endsWith(" (worst)")) {
                        options << option.left(option.length() - 8);
                    } else if (option.endsWith(" (best)")) {
                        options << option.left(option.length() - 7);
                    } else {
                        options << option;
                    }
                }

                cb(options);
            }
        });

    p->setArguments({channelURL, "--default-stream=KKona"});

    p->start();
}

void openStreamlink(const QString &channelURL, const QString &quality,
                    QStringList extraArguments)
{
    auto app = getApp();

    QStringList arguments;

    QString additionalOptions = getSettings()->streamlinkOpts.getValue();
    if (!additionalOptions.isEmpty()) {
        arguments << getSettings()->streamlinkOpts;
    }

    arguments.append(extraArguments);

    arguments << channelURL;

    if (!quality.isEmpty()) {
        arguments << quality;
    }

    bool res = QProcess::startDetached(getStreamlinkProgram() + " " +
                                       QString(arguments.join(' ')));

    if (!res) {
        showStreamlinkNotFoundError();
    }
}

void openStreamlinkForChannel(const QString &channel)
{
    auto app = getApp();

    QString channelURL = "twitch.tv/" + channel;

    QString preferredQuality = getSettings()->preferredQuality;
    preferredQuality = preferredQuality.toLower();

    if (preferredQuality == "choose") {
        getStreamQualities(channelURL, [=](QStringList qualityOptions) {
            QualityPopup::showDialog(channel, qualityOptions);
        });

        return;
    }

    QStringList args;

    // Quality converted from Chatterino format to Streamlink format
    QString quality;
    // Streamlink qualities to exclude
    QString exclude;

    if (preferredQuality == "high") {
        exclude = ">720p30";
        quality = "high,best";
    } else if (preferredQuality == "medium") {
        exclude = ">540p30";
        quality = "medium,best";
    } else if (preferredQuality == "low") {
        exclude = ">360p30";
        quality = "low,best";
    } else if (preferredQuality == "audio only") {
        quality = "audio,audio_only";
    } else {
        quality = "best";
    }
    if (!exclude.isEmpty()) {
        args << "--stream-sorting-excludes" << exclude;
    }

    openStreamlink(channelURL, quality, args);
}

}  // namespace chatterino
<|endoftext|>


<commit_before>#include <windows.h>
#include <shellapi.h>
#include <wincrypt.h>
#include <glib.h>

#include <QLibrary>
#include <QPair>
#include <QString>

#include "utils/utils-win.h"

namespace utils {
namespace win {

namespace {
OSVERSIONINFOEX osver; // static variable, all zero
bool osver_failure = false;

// From http://stackoverflow.com/a/36909293/1467959 and http://yamatyuu.net/computer/program/vc2013/rtlgetversion/index.html
typedef void(WINAPI *RtlGetVersion_FUNC)(OSVERSIONINFOEXW *);
BOOL CustomGetVersion(OSVERSIONINFOEX *os)
{
    HMODULE hMod;
    RtlGetVersion_FUNC func;
#ifdef UNICODE
    OSVERSIONINFOEXW *osw = os;
#else
    OSVERSIONINFOEXW o;
    OSVERSIONINFOEXW *osw = &o;
#endif

    hMod = LoadLibrary(TEXT("ntdll.dll"));
    if (hMod) {
        func = (RtlGetVersion_FUNC)GetProcAddress(hMod, "RtlGetVersion");
        if (func == 0) {
            FreeLibrary(hMod);
            return FALSE;
        }
        ZeroMemory(osw, sizeof(*osw));
        osw->dwOSVersionInfoSize = sizeof(*osw);
        func(osw);
#ifndef UNICODE
        os->dwBuildNumber = osw->dwBuildNumber;
        os->dwMajorVersion = osw->dwMajorVersion;
        os->dwMinorVersion = osw->dwMinorVersion;
        os->dwPlatformId = osw->dwPlatformId;
        os->dwOSVersionInfoSize = sizeof(*os);
        DWORD sz = sizeof(os->szCSDVersion);
        WCHAR *src = osw->szCSDVersion;
        unsigned char *dtc = (unsigned char *)os->szCSDVersion;
        while (*src)
            *dtc++ = (unsigned char)*src++;
        *dtc = '\0';
#endif

    } else
        return FALSE;
    FreeLibrary(hMod);
    return TRUE;
}

inline bool isInitializedSystemVersion() { return osver.dwOSVersionInfoSize != 0; }
inline void initializeSystemVersion() {
    if (isInitializedSystemVersion()) {
        return;
    }
    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    // according to the document,
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx
    // this API will be unavailable once windows 10 is out
    if (!CustomGetVersion(&osver)) {
        qWarning("failed to get OS vesion.");
        osver_failure = true;
    }
}

inline bool _isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
{
    initializeSystemVersion();
    if (osver_failure) {
        return false;
    }
#define OSVER_TO_NUM(major, minor, patch) ((major << 20) + (minor << 10) + (patch))
#define OSVER_SYS(ver) OSVER_TO_NUM(ver.dwMajorVersion, ver.dwMinorVersion, ver.wServicePackMajor)
    if (OSVER_SYS(osver) < OSVER_TO_NUM(major, minor, patch)) {
        return false;
    }
#undef OSVER_SYS
#undef OSVER_TO_NUM
    return true;
}

// compile statically
template<unsigned major, unsigned minor, unsigned patch>
inline bool isAtLeastSystemVersion()
{
    return _isAtLeastSystemVersion(major, minor, patch);
}
} // anonymous namesapce

void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch)
{
    initializeSystemVersion();
    // default to XP
    if (osver_failure) {
        *major = 5;
        *minor = 1;
        *patch = 0;
    }
    *major = osver.dwMajorVersion;
    *minor = osver.dwMinorVersion;
    *patch = osver.wServicePackMajor;
}

bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
{
    return _isAtLeastSystemVersion(major, minor, patch);
}

bool isWindowsVistaOrHigher()
{
    return isAtLeastSystemVersion<6, 0, 0>();
}

bool isWindows7OrHigher()
{
    return isAtLeastSystemVersion<6, 1, 0>();
}

bool isWindows8OrHigher()
{
    return isAtLeastSystemVersion<6, 2, 0>();
}

bool isWindows8Point1OrHigher()
{
    return isAtLeastSystemVersion<6, 3, 0>();
}

bool isWindows10OrHigher()
{
    return isAtLeastSystemVersion<10, 0, 0>();
}

typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *);
typedef BOOL (WINAPI *SetProcessDPIAware)();
GetDpiForMonitor getDpiForMonitor;
SetProcessDPIAware setProcessDPIAware;
typedef QPair<qreal, qreal> QDpi;

static inline QDpi monitorDPI(HMONITOR hMonitor)
{
    UINT dpiX;
    UINT dpiY;
    if (SUCCEEDED(getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY)))
        return QDpi(dpiX, dpiY);
    return QDpi(0, 0);
}

static inline QDpi deviceDPI(HDC hdc)
{
    return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
}

static bool monitorData(HMONITOR hMonitor, QDpi *dpi_out)
{
    MONITORINFOEX info;
    memset(&info, 0, sizeof(MONITORINFOEX));
    info.cbSize = sizeof(MONITORINFOEX);
    if (GetMonitorInfo(hMonitor, &info) == FALSE)
        return false;

    if (QString::fromLocal8Bit(info.szDevice) == QLatin1String("WinDisc")) {
        return false;
    } else {
        QDpi dpi = monitorDPI(hMonitor);
        if (dpi.first) {
            *dpi_out = dpi;
            return true;
        } else {
            HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL);
            if (hdc) {
                *dpi_out = deviceDPI(hdc);
                DeleteDC(hdc);
                return true;
            }
        }
    }
    return false;
}

bool monitorEnumCallback(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM p)
{
    QDpi *data = (QDpi *)p;
    if (monitorData(hMonitor, data)) {
        // printf ("dpi = %d %d\n", (int)data->first, (int)data->second);
        return false;
    }
    return true;
}

static bool readDPI(QDpi *dpi)
{
    EnumDisplayMonitors(0, 0, (MONITORENUMPROC)monitorEnumCallback, (LPARAM)dpi);
    return dpi->first != 0;
}

// QT's HDPI doesn't support non-integer scale factors, but QT_SCALE_FACTOR
// environment variable could work with them. So here we calculate the scaling
// factor (by reading the screen DPI), and update the value QT_SCALE_FACTOR with
// it.
//
// NOTE: The code below only supports single monitor. For multiple monitors we
// need to detect the dpi of each monitor and set QT_AUTO_SCREEN_SCALE_FACTOR
// accordingly. We may do that in the future.
bool fixQtHDPINonIntegerScaling()
{
    // Only do this on win8/win10
    if (!isWindows8OrHigher()) {
        return false;
    }
    // Don't overwrite the user sepcified scaling factors
    if (!qgetenv("QT_SCALE_FACTOR").isEmpty() || !qgetenv("QT_SCREEN_SCALE_FACTORS").isEmpty()) {
        return true;
    }
    // Don't overwrite the user sepcified multi-screen scaling factors
    if (!qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR").isEmpty()) {
        return true;
    }

    // GetDpiForMonitor and SetProcessDPIAware are only available on win8/win10.
    //
    // See:
    //   - GetDpiForMonitor https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx
    //   - SetProcessDPIAware https://msdn.microsoft.com/en-us/library/windows/desktop/ms633543(v=vs.85).aspx
    QLibrary shcore_dll(QString("SHCore"));
    getDpiForMonitor = (GetDpiForMonitor)shcore_dll.resolve("GetDpiForMonitor");
    if (getDpiForMonitor == nullptr) {
        return false;
    }

    QLibrary user32_dll(QString("user32"));
    setProcessDPIAware = (SetProcessDPIAware)user32_dll.resolve("SetProcessDPIAware");
    if (setProcessDPIAware == nullptr) {
        return false;
    }

    // Turn off system scaling, otherwise we'll always see a 96 DPI virtual screen.
    if (!setProcessDPIAware()) {
        return false;
    }

    QDpi dpi;
    if (!readDPI(&dpi)) {
        return false;
    }

    if (dpi.first <= 96) {
        return false;
    }

    // See the "DPI and the Desktop Scaling Factor" https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx#dpi_and_the_desktop_scaling_factor
    // Specifically, MSDN says:
    //     96 DPI = 100% scaling
    //     120 DPI = 125% scaling
    //     144 DPI = 150% scaling
    //     192 DPI = 200% scaling
    double scaling_factor = ((double)(dpi.first)) / 96.0;
    QString factor = QString::number(scaling_factor);

    // Use QT_SCREEN_SCALE_FACTORS instead of QT_SCALE_FACTOR. The latter would
    // scale the font, which has already been scaled by the system.
    //
    // See also http://lists.qt-project.org/pipermail/interest/2015-October/019242.html
    g_setenv("QT_SCREEN_SCALE_FACTORS", factor.toUtf8().data(), 1);
    // printf("set QT_SCALE_FACTOR to %s\n", factor.toUtf8().data());
    return true;
}

char *b64encode(const char *input)
{
    char buf[32767] = {0};
    DWORD retlen = 32767;
    CryptBinaryToString((BYTE*) input, strlen(input), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, buf, &retlen);
    return strdup(buf);
}

std::string getLocalPipeName(const char *pipe_name)
{
#if defined(_MSC_VER)
    const DWORD buf_char_count = 32767;
    DWORD buf_char_count_size = buf_char_count;
#else
    DWORD buf_char_count = 32767;
#endif
    char user_name_buf[buf_char_count];

#if defined(_MSC_VER)
    if (GetUserName(user_name_buf, &buf_char_count_size) == 0) {
#else
    if (GetUserName(user_name_buf, &buf_char_count) == 0) {
#endif
        qWarning("Failed to get user name, GLE=%lu\n", GetLastError());
        return pipe_name;
    } else {
        std::string ret(pipe_name);
        char *encoded = b64encode(user_name_buf);
        ret += encoded;
        free(encoded);
        return ret;
    }
}

// Qt's QProcess function cannot invoke programs that require administrator privileges,
// so we need windows api funtion to invoke the program that require adminstrator privileges.
DWORD runShellAsAdministrator(LPCSTR cmd, LPCSTR arg, int n_show)
{
    SHELLEXECUTEINFO shell_exec_info = {0};
    shell_exec_info.cbSize = sizeof(SHELLEXECUTEINFO);
    shell_exec_info.fMask = SEE_MASK_NOCLOSEPROCESS;
    shell_exec_info.hwnd = NULL;
    shell_exec_info.lpVerb = "runas";
    shell_exec_info.lpFile = cmd;
    shell_exec_info.lpParameters = arg;
    shell_exec_info.lpDirectory = NULL;
    shell_exec_info.nShow = n_show;
    shell_exec_info.hInstApp = NULL;

    BOOL ret = ShellExecuteEx(&shell_exec_info);
    WaitForSingleObject(shell_exec_info.hProcess, INFINITE);

    DWORD exit_code=0;
    GetExitCodeProcess(shell_exec_info.hProcess, &exit_code);
    CloseHandle(shell_exec_info.hProcess);
    return exit_code;
}

} // namespace win

} // namespace utils
<commit_msg>Fix an error check in utils (#1426)<commit_after>#include <windows.h>
#include <shellapi.h>
#include <wincrypt.h>
#include <glib.h>

#include <QLibrary>
#include <QPair>
#include <QString>

#include "utils/utils-win.h"

namespace utils {
namespace win {

namespace {
OSVERSIONINFOEX osver; // static variable, all zero
bool osver_failure = false;

// From http://stackoverflow.com/a/36909293/1467959 and http://yamatyuu.net/computer/program/vc2013/rtlgetversion/index.html
typedef void(WINAPI *RtlGetVersion_FUNC)(OSVERSIONINFOEXW *);
BOOL CustomGetVersion(OSVERSIONINFOEX *os)
{
    HMODULE hMod;
    RtlGetVersion_FUNC func;
#ifdef UNICODE
    OSVERSIONINFOEXW *osw = os;
#else
    OSVERSIONINFOEXW o;
    OSVERSIONINFOEXW *osw = &o;
#endif

    hMod = LoadLibrary(TEXT("ntdll.dll"));
    if (hMod) {
        func = (RtlGetVersion_FUNC)GetProcAddress(hMod, "RtlGetVersion");
        if (func == 0) {
            FreeLibrary(hMod);
            return FALSE;
        }
        ZeroMemory(osw, sizeof(*osw));
        osw->dwOSVersionInfoSize = sizeof(*osw);
        func(osw);
#ifndef UNICODE
        os->dwBuildNumber = osw->dwBuildNumber;
        os->dwMajorVersion = osw->dwMajorVersion;
        os->dwMinorVersion = osw->dwMinorVersion;
        os->dwPlatformId = osw->dwPlatformId;
        os->dwOSVersionInfoSize = sizeof(*os);
        DWORD sz = sizeof(os->szCSDVersion);
        WCHAR *src = osw->szCSDVersion;
        unsigned char *dtc = (unsigned char *)os->szCSDVersion;
        while (*src)
            *dtc++ = (unsigned char)*src++;
        *dtc = '\0';
#endif

    } else
        return FALSE;
    FreeLibrary(hMod);
    return TRUE;
}

inline bool isInitializedSystemVersion() { return osver.dwOSVersionInfoSize != 0; }
inline void initializeSystemVersion() {
    if (isInitializedSystemVersion()) {
        return;
    }
    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    // according to the document,
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx
    // this API will be unavailable once windows 10 is out
    if (!CustomGetVersion(&osver)) {
        qWarning("failed to get OS vesion.");
        osver_failure = true;
    }
}

inline bool _isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
{
    initializeSystemVersion();
    if (osver_failure) {
        return false;
    }
#define OSVER_TO_NUM(major, minor, patch) ((major << 20) + (minor << 10) + (patch))
#define OSVER_SYS(ver) OSVER_TO_NUM(ver.dwMajorVersion, ver.dwMinorVersion, ver.wServicePackMajor)
    if (OSVER_SYS(osver) < OSVER_TO_NUM(major, minor, patch)) {
        return false;
    }
#undef OSVER_SYS
#undef OSVER_TO_NUM
    return true;
}

// compile statically
template<unsigned major, unsigned minor, unsigned patch>
inline bool isAtLeastSystemVersion()
{
    return _isAtLeastSystemVersion(major, minor, patch);
}
} // anonymous namesapce

void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch)
{
    initializeSystemVersion();
    // default to XP
    if (osver_failure) {
        *major = 5;
        *minor = 1;
        *patch = 0;
    }
    *major = osver.dwMajorVersion;
    *minor = osver.dwMinorVersion;
    *patch = osver.wServicePackMajor;
}

bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
{
    return _isAtLeastSystemVersion(major, minor, patch);
}

bool isWindowsVistaOrHigher()
{
    return isAtLeastSystemVersion<6, 0, 0>();
}

bool isWindows7OrHigher()
{
    return isAtLeastSystemVersion<6, 1, 0>();
}

bool isWindows8OrHigher()
{
    return isAtLeastSystemVersion<6, 2, 0>();
}

bool isWindows8Point1OrHigher()
{
    return isAtLeastSystemVersion<6, 3, 0>();
}

bool isWindows10OrHigher()
{
    return isAtLeastSystemVersion<10, 0, 0>();
}

typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *);
typedef BOOL (WINAPI *SetProcessDPIAware)();
GetDpiForMonitor getDpiForMonitor;
SetProcessDPIAware setProcessDPIAware;
typedef QPair<qreal, qreal> QDpi;

static inline QDpi monitorDPI(HMONITOR hMonitor)
{
    UINT dpiX;
    UINT dpiY;
    if (SUCCEEDED(getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY)))
        return QDpi(dpiX, dpiY);
    return QDpi(0, 0);
}

static inline QDpi deviceDPI(HDC hdc)
{
    return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
}

static bool monitorData(HMONITOR hMonitor, QDpi *dpi_out)
{
    MONITORINFOEX info;
    memset(&info, 0, sizeof(MONITORINFOEX));
    info.cbSize = sizeof(MONITORINFOEX);
    if (GetMonitorInfo(hMonitor, &info) == FALSE)
        return false;

    if (QString::fromLocal8Bit(info.szDevice) == QLatin1String("WinDisc")) {
        return false;
    } else {
        QDpi dpi = monitorDPI(hMonitor);
        if (dpi.first) {
            *dpi_out = dpi;
            return true;
        } else {
            HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL);
            if (hdc) {
                *dpi_out = deviceDPI(hdc);
                DeleteDC(hdc);
                return true;
            }
        }
    }
    return false;
}

bool monitorEnumCallback(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM p)
{
    QDpi *data = (QDpi *)p;
    if (monitorData(hMonitor, data)) {
        // printf ("dpi = %d %d\n", (int)data->first, (int)data->second);
        return false;
    }
    return true;
}

static bool readDPI(QDpi *dpi)
{
    EnumDisplayMonitors(0, 0, (MONITORENUMPROC)monitorEnumCallback, (LPARAM)dpi);
    return dpi->first != 0;
}

// QT's HDPI doesn't support non-integer scale factors, but QT_SCALE_FACTOR
// environment variable could work with them. So here we calculate the scaling
// factor (by reading the screen DPI), and update the value QT_SCALE_FACTOR with
// it.
//
// NOTE: The code below only supports single monitor. For multiple monitors we
// need to detect the dpi of each monitor and set QT_AUTO_SCREEN_SCALE_FACTOR
// accordingly. We may do that in the future.
bool fixQtHDPINonIntegerScaling()
{
    // Only do this on win8/win10
    if (!isWindows8OrHigher()) {
        return false;
    }
    // Don't overwrite the user sepcified scaling factors
    if (!qgetenv("QT_SCALE_FACTOR").isEmpty() || !qgetenv("QT_SCREEN_SCALE_FACTORS").isEmpty()) {
        return true;
    }
    // Don't overwrite the user sepcified multi-screen scaling factors
    if (!qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR").isEmpty()) {
        return true;
    }

    // GetDpiForMonitor and SetProcessDPIAware are only available on win8/win10.
    //
    // See:
    //   - GetDpiForMonitor https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx
    //   - SetProcessDPIAware https://msdn.microsoft.com/en-us/library/windows/desktop/ms633543(v=vs.85).aspx
    QLibrary shcore_dll(QString("SHCore"));
    getDpiForMonitor = (GetDpiForMonitor)shcore_dll.resolve("GetDpiForMonitor");
    if (getDpiForMonitor == nullptr) {
        return false;
    }

    QLibrary user32_dll(QString("user32"));
    setProcessDPIAware = (SetProcessDPIAware)user32_dll.resolve("SetProcessDPIAware");
    if (setProcessDPIAware == nullptr) {
        return false;
    }

    // Turn off system scaling, otherwise we'll always see a 96 DPI virtual screen.
    if (!setProcessDPIAware()) {
        return false;
    }

    QDpi dpi;
    if (!readDPI(&dpi)) {
        return false;
    }

    if (dpi.first <= 96) {
        return false;
    }

    // See the "DPI and the Desktop Scaling Factor" https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx#dpi_and_the_desktop_scaling_factor
    // Specifically, MSDN says:
    //     96 DPI = 100% scaling
    //     120 DPI = 125% scaling
    //     144 DPI = 150% scaling
    //     192 DPI = 200% scaling
    double scaling_factor = ((double)(dpi.first)) / 96.0;
    QString factor = QString::number(scaling_factor);

    // Use QT_SCREEN_SCALE_FACTORS instead of QT_SCALE_FACTOR. The latter would
    // scale the font, which has already been scaled by the system.
    //
    // See also http://lists.qt-project.org/pipermail/interest/2015-October/019242.html
    g_setenv("QT_SCREEN_SCALE_FACTORS", factor.toUtf8().data(), 1);
    // printf("set QT_SCALE_FACTOR to %s\n", factor.toUtf8().data());
    return true;
}

char *b64encode(const char *input)
{
    char buf[32767] = {0};
    DWORD retlen = 32767;
    if (!CryptBinaryToString((BYTE*) input, strlen(input), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, buf, &retlen)) {
        return NULL;
    }
    return strdup(buf);
}

std::string getLocalPipeName(const char *pipe_name)
{
#if defined(_MSC_VER)
    const DWORD buf_char_count = 32767;
    DWORD buf_char_count_size = buf_char_count;
#else
    DWORD buf_char_count = 32767;
#endif
    char user_name_buf[buf_char_count];

#if defined(_MSC_VER)
    if (GetUserName(user_name_buf, &buf_char_count_size) == 0) {
#else
    if (GetUserName(user_name_buf, &buf_char_count) == 0) {
#endif
        qWarning("Failed to get user name, GLE=%lu\n", GetLastError());
        return pipe_name;
    } else {
        std::string ret(pipe_name);
        char *encoded = b64encode(user_name_buf);
        if (encoded) {
            ret += encoded;
            free(encoded);
        }
        return ret;
    }
}

// Qt's QProcess function cannot invoke programs that require administrator privileges,
// so we need windows api funtion to invoke the program that require adminstrator privileges.
DWORD runShellAsAdministrator(LPCSTR cmd, LPCSTR arg, int n_show)
{
    SHELLEXECUTEINFO shell_exec_info = {0};
    shell_exec_info.cbSize = sizeof(SHELLEXECUTEINFO);
    shell_exec_info.fMask = SEE_MASK_NOCLOSEPROCESS;
    shell_exec_info.hwnd = NULL;
    shell_exec_info.lpVerb = "runas";
    shell_exec_info.lpFile = cmd;
    shell_exec_info.lpParameters = arg;
    shell_exec_info.lpDirectory = NULL;
    shell_exec_info.nShow = n_show;
    shell_exec_info.hInstApp = NULL;

    BOOL ret = ShellExecuteEx(&shell_exec_info);
    WaitForSingleObject(shell_exec_info.hProcess, INFINITE);

    DWORD exit_code=0;
    GetExitCodeProcess(shell_exec_info.hProcess, &exit_code);
    CloseHandle(shell_exec_info.hProcess);
    return exit_code;
}

} // namespace win

} // namespace utils
<|endoftext|>


<commit_before>/*

*/

#include "lineFollowing.h"

using namespace std;
using namespace cv;

ControlMovements lineFollowingControl() {

  line_main();

  return ControlMovements();
}

void line_main() {
//  printf("Hello, this is Caleb\n");

  VideoCapture cap("../../tests/videos/top_down_4.m4v");
  if (!cap.isOpened())  // check if we succeeded
    return;

  namedWindow("edges", CV_WINDOW_NORMAL);
  Mat edges;
  for (; ;) {
    Mat mask;
    Mat frame, gray;
    cap >> frame; // get a new frame from camera
    cvtColor(frame, gray, CV_BGR2HSV);

    Scalar low, high;
    low = Scalar(30, 0, 240);
    high = Scalar(80, 70, 255);

    inRange(gray, low, high, mask);

    vector <Vec4i> lines;
    HoughLinesP(mask, lines, 1, CV_PI / 180, 100, 100, 10);

    printf("Adding in %d lines\n", (int) lines.size());
    for (size_t i = 0; i < lines.size(); i++) {
      Vec4i l = lines[i];
      line(frame, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, CV_AA);
    }

    imshow("edges", frame);
    if (waitKey(30) >= 0) break;
  }
  // the camera will be deinitialized automatically in VideoCapture destructor
  return;
}
<commit_msg>testing lines on mask<commit_after>/*

*/

#include "lineFollowing.h"

using namespace std;
using namespace cv;

ControlMovements lineFollowingControl() {

  line_main();

  return ControlMovements();
}

void line_main() {
//  printf("Hello, this is Caleb\n");

  VideoCapture cap("../../tests/videos/top_down_4.m4v");
  if (!cap.isOpened())  // check if we succeeded
    return;

  namedWindow("edges", CV_WINDOW_NORMAL);
  Mat edges;
  for (; ;) {
    Mat mask, hsv_mask;
    Mat frame, gray;
    cap >> frame; // get a new frame from camera
    cvtColor(frame, gray, CV_BGR2HSV);

    Scalar low, high;
    low = Scalar(30, 0, 240);
    high = Scalar(80, 70, 255);

    inRange(gray, low, high, mask);
//    cvtColor(mask, hsv_mask, CV_HS);
    hsv_mask = mask;
    vector <Vec4i> lines;
    HoughLinesP(mask, lines, 1, CV_PI / 180, 100, 100, 10);

    printf("Adding in %d lines\n", (int) lines.size());
    for (size_t i = 0; i < lines.size(); i++) {
      Vec4i l = lines[i];
      line(hsv_mask, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, CV_AA);
    }

    imshow("edges", hsv_mask);
    if (waitKey(30) >= 0) break;
  }
  // the camera will be deinitialized automatically in VideoCapture destructor
  return;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qlandmarkboxfilter.h"

QTM_BEGIN_NAMESPACE

/*!
    \class QLandmarkBoxFilter
    \brief The QLandmarkBoxFilter class is used to search for landmarks within a given bounding box.
    \ingroup location
*/

/*!
    Creates a filter that will search for landmarks within a bounding
    box defined by the \a topLeft and \a bottomRight coordinates.
*/
QLandmarkBoxFilter::QLandmarkBoxFilter(const QGeoCoordinate &topLeft,
                                       const QGeoCoordinate &bottomRight)
{
    //TODO: implement
}

/*!
    Destroys the filter.
*/
QLandmarkBoxFilter::~QLandmarkBoxFilter()
{
    //TODO: implement
}

/*!
    Returns the top-left corner of the bounding box this filter uses
    to select landmarks.
*/
QGeoCoordinate QLandmarkBoxFilter::topLeftCoordinate()
{
}

/*!
    Sets the \a topLeft corner of the bounding box this filter uses to
    select landmarks.
*/
void QLandmarkBoxFilter::setTopLeftCoordinate(const QGeoCoordinate &topLeft)
{
}

/*!
    Returns the bottom-right coordinate of the bounding box this filter uses
    to select landmarks.
*/
QGeoCoordinate QLandmarkBoxFilter::bottomRightCoordinate()
{
}

/*!
    Sets the \a bottomRight coordinate of the bounding box this filter uses to
    select landmarks.
*/
void QLandmarkBoxFilter::setBottomRightCoordinate(const QGeoCoordinate &bottomRight)
{
}

QTM_END_NAMESPACE
<commit_msg>Further compile fixes for WinXP.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qlandmarkboxfilter.h"

QTM_BEGIN_NAMESPACE

/*!
    \class QLandmarkBoxFilter
    \brief The QLandmarkBoxFilter class is used to search for landmarks within a given bounding box.
    \ingroup location
*/

/*!
    Creates a filter that will search for landmarks within a bounding
    box defined by the \a topLeft and \a bottomRight coordinates.
*/
QLandmarkBoxFilter::QLandmarkBoxFilter(const QGeoCoordinate &topLeft,
                                       const QGeoCoordinate &bottomRight)
{
    //TODO: implement
}

/*!
    Destroys the filter.
*/
QLandmarkBoxFilter::~QLandmarkBoxFilter()
{
    //TODO: implement
}

/*!
    Returns the top-left corner of the bounding box this filter uses
    to select landmarks.
*/
QGeoCoordinate QLandmarkBoxFilter::topLeftCoordinate()
{
    return QGeoCoordinate();
}

/*!
    Sets the \a topLeft corner of the bounding box this filter uses to
    select landmarks.
*/
void QLandmarkBoxFilter::setTopLeftCoordinate(const QGeoCoordinate &topLeft)
{
}

/*!
    Returns the bottom-right coordinate of the bounding box this filter uses
    to select landmarks.
*/
QGeoCoordinate QLandmarkBoxFilter::bottomRightCoordinate()
{
    return QGeoCoordinate();
}

/*!
    Sets the \a bottomRight coordinate of the bounding box this filter uses to
    select landmarks.
*/
void QLandmarkBoxFilter::setBottomRightCoordinate(const QGeoCoordinate &bottomRight)
{
}

QTM_END_NAMESPACE
<|endoftext|>