<commit_before>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <hadesmem/find_pattern.hpp>

#define BOOST_TEST_MODULE find_pattern
#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/test/unit_test.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/error.hpp>
#include <hadesmem/config.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/detail/initialize.hpp>

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

// TODO: Clean up, expand, fix, etc these tests.
// TODO: Add more tests (e.g. stream overload tests).

BOOST_AUTO_TEST_CASE(initialize)
{
    hadesmem::detail::InitializeAll();
}

// Using an underscore to avoid a variable shadowing waring under Clang
// and GCC.
// TODO: Fix this.
BOOST_AUTO_TEST_CASE(find_pattern_)
{
    hadesmem::Process const process(::GetCurrentProcessId());

    HMODULE const self = GetModuleHandle(nullptr);
    BOOST_REQUIRE(self != nullptr);

    hadesmem::FindPattern find_pattern(process, self);

    // Create pattern scanner targetting self (using default constructor this
    // time)
    find_pattern = hadesmem::FindPattern(process, nullptr);
    // Ensure constructor throws if an invalid module handle is specified
    // TODO: Fix this.
    //BOOST_CHECK_THROW(find_pattern = hadesmem::FindPattern(process,
    //  reinterpret_cast<HMODULE>(-1)), hadesmem::Error);

    // Scan for predicatable byte mask
    auto const nop = find_pattern.Find(L"90",
        hadesmem::FindPatternFlags::kNone);
    // Ensure pattern was found
    BOOST_CHECK(nop != nullptr);
    // Ensure pattern address is valid
    BOOST_CHECK_GT(nop, self);
    // Scan again for same pattern, this time specifying a name
    find_pattern.Find(L"90", L"Nop", hadesmem::FindPatternFlags::kNone);
    // Ensure pattern is found, is added to the named map, and is equal to
    // the previously found instance
    BOOST_CHECK_EQUAL(nop, find_pattern[L"Nop"]);
    // Ensure named map is the expected size
    BOOST_CHECK_EQUAL(find_pattern.GetAddresses().size(), 1UL);
    // Scan again for same pattern, this time specifying the relative address
    // flag
    auto const nop_rel = find_pattern.Find(L"90",
        hadesmem::FindPatternFlags::kRelativeAddress);
    // Ensure the relative address is correct
    BOOST_CHECK_EQUAL(static_cast<PBYTE>(nop_rel)+
        reinterpret_cast<DWORD_PTR>(self), nop);
    // Test stream-based pattern scanner by scanning for the same pattern,
    // with a different name
    hadesmem::Pattern nop_pattern(find_pattern, L"90", L"NopPlus1",
        hadesmem::FindPatternFlags::kNone);
    // Apply 'Add' manipulator to pattern and save back to parent
    nop_pattern << hadesmem::pattern_manipulators::Add(1) <<
        hadesmem::pattern_manipulators::Save();
    // Ensure manipulator was correctly applied
    BOOST_CHECK_EQUAL(nop_pattern.GetAddress(), static_cast<PBYTE>(nop)+1);
    // Ensure pattern result was saved back to parent
    BOOST_CHECK_EQUAL(nop_pattern.GetAddress(), find_pattern[L"NopPlus1"]);
    // Ensure named map is the expected size
    BOOST_CHECK_EQUAL(find_pattern.GetAddresses().size(), 2UL);

    // Scan for predictable byte mask (including wildcard)
    auto const zeros = find_pattern.Find(L"00 ?? 00",
        hadesmem::FindPatternFlags::kNone);
    // Ensure pattern was found
    BOOST_CHECK(zeros != nullptr);
    // Ensure pattern address is valid
    BOOST_CHECK_GT(zeros, GetModuleHandle(nullptr));
    // Scan again for same pattern, this time specifying a name
    find_pattern.Find(L"00 ?? 00", L"Zeros",
        hadesmem::FindPatternFlags::kNone);
    // Ensure pattern is found, is added to the named map, and is equal to
    // the previously found instance
    BOOST_CHECK_EQUAL(zeros, find_pattern[L"Zeros"]);
    // Ensure named map is the expected size
    BOOST_CHECK_EQUAL(find_pattern.GetAddresses().size(), 3UL);
    // Ensure this pattern (00 ?? 00) does not match the earlier pattern (90)
    BOOST_CHECK(nop != zeros);
    // Scan again for same pattern, this time specifying the relative address
    // flag
    auto const zeros_rel = find_pattern.Find(L"00 ?? 00",
        hadesmem::FindPatternFlags::kRelativeAddress);
    // Ensure the relative address is correct
    BOOST_CHECK_EQUAL(static_cast<PBYTE>(zeros_rel)+
        reinterpret_cast<DWORD_PTR>(self), zeros);
    // Test stream-based pattern scanner by scanning for the same pattern,
    // with a different name
    hadesmem::Pattern zeros_pattern(find_pattern, L"00 ?? 00",
        L"ZerosMinus1", hadesmem::FindPatternFlags::kNone);
    // Apply 'Sub' manipulator to pattern and save back to parent
    zeros_pattern << hadesmem::pattern_manipulators::Sub(1) <<
        hadesmem::pattern_manipulators::Save();
    // Ensure manipulator was correctly applied
    BOOST_CHECK_EQUAL(static_cast<PVOID>(zeros_pattern.GetAddress()),
        static_cast<PVOID>(static_cast<PBYTE>(zeros)-1));
    // Ensure pattern result was saved back to parent
    BOOST_CHECK_EQUAL(zeros_pattern.GetAddress(),
        find_pattern[L"ZerosMinus1"]);
    // Ensure named map is the expected size
    BOOST_CHECK_EQUAL(find_pattern.GetAddresses().size(), 4UL);

    // Test stream-based pattern scanner by scanning for an instruction with
    // a known relative operand. We should ensure that we're not going to hit
    // this particular byte accidently as part of the operand of another
    // instruction, but for now lets just ignore that possibility. The test
    // will (or should) fail in that case.
    hadesmem::Pattern call_pattern(find_pattern, L"E8",
        hadesmem::FindPatternFlags::kRelativeAddress);
    // Ensure pattern was found
    BOOST_CHECK(call_pattern.GetAddress() != nullptr);
    // The instruction is a 'Call' instruction, so add one byte to move
    // past the instruction, then perform a relative dereference using the
    // instruction size and operand offset (5 and 1 respectively in this
    // case, for a 32-bit relative call).
    call_pattern << hadesmem::pattern_manipulators::Add(1) <<
        hadesmem::pattern_manipulators::Rel(5, 1);
    // Ensure pattern was found
    BOOST_CHECK(call_pattern.GetAddress() != nullptr);

    // Todo: pattern_manipulators::Lea test

    // Test pattern file, including scan flags, pattern matching, and
    // optional manipulators. Use the same patterns we have been using
    // already so we can check their validity.
    std::wstring const pattern_file_data =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"></Flag>
    <Flag Name="ThrowOnUnmatch"></Flag>
    <Pattern Name="First Call" Data="E8">
      <Manipulator Name="Add" Operand1="1"></Manipulator>
      <Manipulator Name="Rel" Operand1="5" Operand2="1"></Manipulator>
    </Pattern>
    <Pattern Name="Zeros New" Data="00 ?? 00">
      <Manipulator Name="Add" Operand1="1"></Manipulator>
      <Manipulator Name="Sub" Operand1="1"></Manipulator>
    </Pattern>
    <Pattern Name="Nop Other" Data="90"></Pattern>
  </FindPattern>
</HadesMem>
)";
    find_pattern.LoadFileMemory(pattern_file_data);
    // Ensure all patterns match previous scans
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"First Call"),
        call_pattern.GetAddress());
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"First Call"),
        find_pattern[L"First Call"]);
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"Zeros New"),
        zeros_rel);
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"Zeros New"),
        find_pattern[L"Zeros New"]);
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"Nop Other"),
        nop_rel);
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"Nop Other"),
        find_pattern[L"Nop Other"]);

    // Test pattern file, using various types of invalid input.
    std::wstring const pattern_file_data_invalid1 =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag>InvalidFlag</Flag>
  </FindPattern>
</HadesMem>
)";
    BOOST_CHECK_THROW(find_pattern.LoadFileMemory(
        pattern_file_data_invalid1),
        hadesmem::Error);
    std::wstring const pattern_file_data_invalid2 =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag>RelativeAddress</Flag>
    <Flag>ThrowOnUnmatch</Flag>
    <Manipulator Name="Add" Operand1="1"></Manipulator>
  </FindPattern>
</HadesMem>
)";
    BOOST_CHECK_THROW(find_pattern.LoadFileMemory(
        pattern_file_data_invalid2),
        hadesmem::Error);
    std::wstring const pattern_file_data_invalid3 =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag>RelativeAddress</Flag>
    <Flag>ThrowOnUnmatch</Flag>
    <Pattern Name="Foo" Data="ZZ"></Pattern>
  </FindPattern>
</HadesMem>
)";
    BOOST_CHECK_THROW(find_pattern.LoadFileMemory(
        pattern_file_data_invalid3),
        hadesmem::Error);
    std::wstring const pattern_file_data_invalid4 =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag>RelativeAddress</Flag>
    <Flag>ThrowOnUnmatch</Flag>
    <Pattern></Pattern>
  </FindPattern>
</HadesMem>
)";
    BOOST_CHECK_THROW(find_pattern.LoadFileMemory(
        pattern_file_data_invalid4),
        hadesmem::Error);

    // Todo: LoadFile test

    // Perform a full wildcard scan twice and ensure that both scans return
    // the same address
    auto const nops_any = find_pattern.Find(L"?? ?? ?? ?? ??",
        hadesmem::FindPatternFlags::kNone);
    auto const int3s_any = find_pattern.Find(L"?? ?? ?? ?? ??",
        hadesmem::FindPatternFlags::kNone);
    BOOST_CHECK_EQUAL(nops_any, int3s_any);
    // Ensure address is valid
    BOOST_CHECK_GT(nops_any, GetModuleHandle(nullptr));
    // Perform scan again with relative address flag
    auto const nops_any_rel = find_pattern.Find(L"?? ?? ?? ?? ??",
        hadesmem::FindPatternFlags::kRelativeAddress);
    // Ensure address is valid
    BOOST_CHECK_EQUAL(static_cast<PBYTE>(nops_any_rel)+
        reinterpret_cast<DWORD_PTR>(self), nops_any);

    // Check ThrowOnUnmatch flag
    BOOST_CHECK_THROW(find_pattern.Find(L"AA BB CC DD EE FF 11 22 33 44 55 "
        L"66 77 88 99 00 11 33 33 77",
        hadesmem::FindPatternFlags::kThrowOnUnmatch),
        hadesmem::Error);

    // Check ScanData flag
    // Note: Pattern is for narrow string 'FindPattern' (without quotes)
    auto const find_pattern_str = find_pattern.Find(L"46 69 6E 64 50 61 74 "
        L"65 72 6E", hadesmem::FindPatternFlags::kScanData);
    BOOST_CHECK(find_pattern_str != nullptr);

    // Check conversion failures throw
    BOOST_CHECK_THROW(find_pattern.Find(L"ZZ",
        hadesmem::FindPatternFlags::kNone), hadesmem::Error);

    // Check conversion failures throw
    // Code changes now mean this causes an assert.
    //BOOST_CHECK_THROW(find_pattern.Find(L"",
    //  hadesmem::FindPatternFlags::kNone), hadesmem::Error);
}
<commit_msg>* [FindPattern] Fix test.<commit_after>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <hadesmem/find_pattern.hpp>

#define BOOST_TEST_MODULE find_pattern
#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/test/unit_test.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/error.hpp>
#include <hadesmem/config.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/detail/initialize.hpp>

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

// TODO: Clean up, expand, fix, etc these tests.
// TODO: Add more tests (e.g. stream overload tests).

BOOST_AUTO_TEST_CASE(initialize)
{
    hadesmem::detail::InitializeAll();
}

// Using an underscore to avoid a variable shadowing waring under Clang
// and GCC.
// TODO: Fix this.
BOOST_AUTO_TEST_CASE(find_pattern_)
{
    hadesmem::Process const process(::GetCurrentProcessId());

    HMODULE const self = GetModuleHandle(nullptr);
    BOOST_REQUIRE(self != nullptr);

    hadesmem::FindPattern find_pattern(process, self);

    // Create pattern scanner targetting self (using default constructor this
    // time)
    find_pattern = hadesmem::FindPattern(process, nullptr);
    // Ensure constructor throws if an invalid module handle is specified
    // TODO: Fix this.
    //BOOST_CHECK_THROW(find_pattern = hadesmem::FindPattern(process,
    //  reinterpret_cast<HMODULE>(-1)), hadesmem::Error);

    // Scan for predicatable byte mask
    auto const nop = find_pattern.Find(L"90",
        hadesmem::FindPatternFlags::kNone);
    // Ensure pattern was found
    BOOST_CHECK(nop != nullptr);
    // Ensure pattern address is valid
    BOOST_CHECK_GT(nop, self);
    // Scan again for same pattern, this time specifying a name
    find_pattern.Find(L"90", L"Nop", hadesmem::FindPatternFlags::kNone);
    // Ensure pattern is found, is added to the named map, and is equal to
    // the previously found instance
    BOOST_CHECK_EQUAL(nop, find_pattern[L"Nop"]);
    // Ensure named map is the expected size
    BOOST_CHECK_EQUAL(find_pattern.GetAddresses().size(), 1UL);
    // Scan again for same pattern, this time specifying the relative address
    // flag
    auto const nop_rel = find_pattern.Find(L"90",
        hadesmem::FindPatternFlags::kRelativeAddress);
    // Ensure the relative address is correct
    BOOST_CHECK_EQUAL(static_cast<PBYTE>(nop_rel)+
        reinterpret_cast<DWORD_PTR>(self), nop);
    // Test stream-based pattern scanner by scanning for the same pattern,
    // with a different name
    hadesmem::Pattern nop_pattern(find_pattern, L"90", L"NopPlus1",
        hadesmem::FindPatternFlags::kNone);
    // Apply 'Add' manipulator to pattern and save back to parent
    nop_pattern << hadesmem::pattern_manipulators::Add(1) <<
        hadesmem::pattern_manipulators::Save();
    // Ensure manipulator was correctly applied
    BOOST_CHECK_EQUAL(nop_pattern.GetAddress(), static_cast<PBYTE>(nop)+1);
    // Ensure pattern result was saved back to parent
    BOOST_CHECK_EQUAL(nop_pattern.GetAddress(), find_pattern[L"NopPlus1"]);
    // Ensure named map is the expected size
    BOOST_CHECK_EQUAL(find_pattern.GetAddresses().size(), 2UL);

    // Scan for predictable byte mask (including wildcard)
    auto const zeros = find_pattern.Find(L"00 ?? 00",
        hadesmem::FindPatternFlags::kNone);
    // Ensure pattern was found
    BOOST_CHECK(zeros != nullptr);
    // Ensure pattern address is valid
    BOOST_CHECK_GT(zeros, GetModuleHandle(nullptr));
    // Scan again for same pattern, this time specifying a name
    find_pattern.Find(L"00 ?? 00", L"Zeros",
        hadesmem::FindPatternFlags::kNone);
    // Ensure pattern is found, is added to the named map, and is equal to
    // the previously found instance
    BOOST_CHECK_EQUAL(zeros, find_pattern[L"Zeros"]);
    // Ensure named map is the expected size
    BOOST_CHECK_EQUAL(find_pattern.GetAddresses().size(), 3UL);
    // Ensure this pattern (00 ?? 00) does not match the earlier pattern (90)
    BOOST_CHECK(nop != zeros);
    // Scan again for same pattern, this time specifying the relative address
    // flag
    auto const zeros_rel = find_pattern.Find(L"00 ?? 00",
        hadesmem::FindPatternFlags::kRelativeAddress);
    // Ensure the relative address is correct
    BOOST_CHECK_EQUAL(static_cast<PBYTE>(zeros_rel)+
        reinterpret_cast<DWORD_PTR>(self), zeros);
    // Test stream-based pattern scanner by scanning for the same pattern,
    // with a different name
    hadesmem::Pattern zeros_pattern(find_pattern, L"00 ?? 00",
        L"ZerosMinus1", hadesmem::FindPatternFlags::kNone);
    // Apply 'Sub' manipulator to pattern and save back to parent
    zeros_pattern << hadesmem::pattern_manipulators::Sub(1) <<
        hadesmem::pattern_manipulators::Save();
    // Ensure manipulator was correctly applied
    BOOST_CHECK_EQUAL(static_cast<PVOID>(zeros_pattern.GetAddress()),
        static_cast<PVOID>(static_cast<PBYTE>(zeros)-1));
    // Ensure pattern result was saved back to parent
    BOOST_CHECK_EQUAL(zeros_pattern.GetAddress(),
        find_pattern[L"ZerosMinus1"]);
    // Ensure named map is the expected size
    BOOST_CHECK_EQUAL(find_pattern.GetAddresses().size(), 4UL);

    // Test stream-based pattern scanner by scanning for an instruction with
    // a known relative operand. We should ensure that we're not going to hit
    // this particular byte accidently as part of the operand of another
    // instruction, but for now lets just ignore that possibility. The test
    // will (or should) fail in that case.
    hadesmem::Pattern call_pattern(find_pattern, L"E8",
        hadesmem::FindPatternFlags::kRelativeAddress);
    // Ensure pattern was found
    BOOST_CHECK(call_pattern.GetAddress() != nullptr);
    // The instruction is a 'Call' instruction, so add one byte to move
    // past the instruction, then perform a relative dereference using the
    // instruction size and operand offset (5 and 1 respectively in this
    // case, for a 32-bit relative call).
    call_pattern << hadesmem::pattern_manipulators::Add(1) <<
        hadesmem::pattern_manipulators::Rel(5, 1);
    // Ensure pattern was found
    BOOST_CHECK(call_pattern.GetAddress() != nullptr);

    // Todo: pattern_manipulators::Lea test

    // Test pattern file, including scan flags, pattern matching, and
    // optional manipulators. Use the same patterns we have been using
    // already so we can check their validity.
    std::wstring const pattern_file_data =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="First Call" Data="E8">
      <Manipulator Name="Add" Operand1="1"></Manipulator>
      <Manipulator Name="Rel" Operand1="5" Operand2="1"></Manipulator>
    </Pattern>
    <Pattern Name="Zeros New" Data="00 ?? 00">
      <Manipulator Name="Add" Operand1="1"></Manipulator>
      <Manipulator Name="Sub" Operand1="1"></Manipulator>
    </Pattern>
    <Pattern Name="Nop Other" Data="90"/>
  </FindPattern>
</HadesMem>
)";
    find_pattern.LoadFileMemory(pattern_file_data);
    // Ensure all patterns match previous scans
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"First Call"),
        call_pattern.GetAddress());
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"First Call"),
        find_pattern[L"First Call"]);
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"Zeros New"),
        zeros_rel);
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"Zeros New"),
        find_pattern[L"Zeros New"]);
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"Nop Other"),
        nop_rel);
    BOOST_CHECK_EQUAL(find_pattern.Lookup(L"Nop Other"),
        find_pattern[L"Nop Other"]);

    // Test pattern file, using various types of invalid input.
    // TODO: Fix the test to ensure we get the error we're expecting, rather
    // than just any error.
    std::wstring const pattern_file_data_invalid1 =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="InvalidFlag"></Flag>
  </FindPattern>
</HadesMem>
)";
    BOOST_CHECK_THROW(find_pattern.LoadFileMemory(
        pattern_file_data_invalid1),
        hadesmem::Error);

    std::wstring const pattern_file_data_invalid2 =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"></Flag>
    <Flag Name="ThrowOnUnmatch"></Flag>
    <Pattern Name="Foo" Data="ZZ"></Pattern>
  </FindPattern>
</HadesMem>
)";
    BOOST_CHECK_THROW(find_pattern.LoadFileMemory(
        pattern_file_data_invalid2),
        hadesmem::Error);

    std::wstring const pattern_file_data_invalid3 =
        LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"></Flag>
    <Flag Name="ThrowOnUnmatch"></Flag>
    <Pattern></Pattern>
  </FindPattern>
</HadesMem>
)";
    BOOST_CHECK_THROW(find_pattern.LoadFileMemory(
        pattern_file_data_invalid3),
        hadesmem::Error);

    // Todo: LoadFile test

    // Perform a full wildcard scan twice and ensure that both scans return
    // the same address
    auto const nops_any = find_pattern.Find(L"?? ?? ?? ?? ??",
        hadesmem::FindPatternFlags::kNone);
    auto const int3s_any = find_pattern.Find(L"?? ?? ?? ?? ??",
        hadesmem::FindPatternFlags::kNone);
    BOOST_CHECK_EQUAL(nops_any, int3s_any);
    // Ensure address is valid
    BOOST_CHECK_GT(nops_any, GetModuleHandle(nullptr));
    // Perform scan again with relative address flag
    auto const nops_any_rel = find_pattern.Find(L"?? ?? ?? ?? ??",
        hadesmem::FindPatternFlags::kRelativeAddress);
    // Ensure address is valid
    BOOST_CHECK_EQUAL(static_cast<PBYTE>(nops_any_rel)+
        reinterpret_cast<DWORD_PTR>(self), nops_any);

    // Check ThrowOnUnmatch flag
    BOOST_CHECK_THROW(find_pattern.Find(L"AA BB CC DD EE FF 11 22 33 44 55 "
        L"66 77 88 99 00 11 33 33 77",
        hadesmem::FindPatternFlags::kThrowOnUnmatch),
        hadesmem::Error);

    // Check ScanData flag
    // Note: Pattern is for narrow string 'FindPattern' (without quotes)
    auto const find_pattern_str = find_pattern.Find(L"46 69 6E 64 50 61 74 "
        L"74 65 72 6E", hadesmem::FindPatternFlags::kScanData);
    BOOST_CHECK(find_pattern_str != nullptr);

    // Check conversion failures throw
    BOOST_CHECK_THROW(find_pattern.Find(L"ZZ",
        hadesmem::FindPatternFlags::kNone), hadesmem::Error);

    // Check conversion failures throw
    // Code changes now mean this causes an assert.
    //BOOST_CHECK_THROW(find_pattern.Find(L"",
    //  hadesmem::FindPatternFlags::kNone), hadesmem::Error);
}
<|endoftext|>


<commit_before>#ifndef NUMTYPE_ADAPTERS_EIGEN_HPP_G9DJMXVS
#define NUMTYPE_ADAPTERS_EIGEN_HPP_G9DJMXVS

#include <ndata/algorithm/numtype_adapter_fundamental.hpp>

namespace ndata {
namespace helpers {

template <typename EigenT>
using DerivedOf = typename std::result_of<typename EigenT::derived>::type;

template <typename EigenT>
using DenseBaseParent = Eigen::DenseBase<DerivedOf<EigenT>>;

template <typename T>
struct numtype_adapter<
    T,
    typename std::enable_if<
        std::is_base_of<
            Eigen::EigenBase<T>,
            T
        >::value
    >::type
>
{

    static const
    T ZERO;

};

template <typename T>
const T
numtype_adapter<
    T,
    typename std::enable_if<
        std::is_base_of<
            Eigen::EigenBase<T>,
            T
        >::value
    >::type
>::ZERO = T::Zero();

} //end namespace ndata
} //end namespace helpers

#endif /* end of include guard: NUMTYPE_ADAPTERS_EIGEN_HPP_G9DJMXVS */
<commit_msg>minor<commit_after>#ifndef NUMTYPE_ADAPTERS_EIGEN_HPP_G9DJMXVS
#define NUMTYPE_ADAPTERS_EIGEN_HPP_G9DJMXVS

#include <ndata/algorithm/numtype_adapter_fundamental.hpp>

//TODO test this with interp

namespace ndata {
namespace helpers {

template <typename EigenT>
using DerivedOf = typename std::result_of<typename EigenT::derived>::type;

template <typename EigenT>
using DenseBaseParent = Eigen::DenseBase<DerivedOf<EigenT>>;

template <typename T>
struct numtype_adapter<
    T,
    typename std::enable_if<
        std::is_base_of<
            Eigen::EigenBase<T>,
            T
        >::value
    >::type
>
{

    static const
    T ZERO;

};

template <typename T>
const T
numtype_adapter<
    T,
    typename std::enable_if<
        std::is_base_of<
            Eigen::EigenBase<T>,
            T
        >::value
    >::type
>::ZERO = T::Zero();

} //end namespace ndata
} //end namespace helpers

#endif /* end of include guard: NUMTYPE_ADAPTERS_EIGEN_HPP_G9DJMXVS */
<|endoftext|>


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

#include "glwidget.h"
#include <QPainter>
#include <QPaintEngine>
#include <QMouseEvent>
#include <math.h>
#include <map>

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(parent)
{
    qtLogo = true;
    m_fScale = 1.0;
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setAutoBufferSwap(false);

    mTranslateX = 0;
    mTranslateY = 0;
    mDragX = 0;
    mDragY = 0;
    mSelectionIndex=0;
    mShowScreenShot = false;
    mDragging = false;

    connect(&mAnimationTimer,SIGNAL(timeout()),SLOT(animate()));
    setMouseTracking(true);

    mLogo = QPixmap(":/stagehand/splash.png");

}

GLWidget::~GLWidget()
{
}

void GLWidget::setProjectionMatrix(QMatrix4x4 projMatrix)
{
    mProjectionMatrix = projMatrix;
}

void GLWidget::setViewMatrix(QMatrix4x4 viewMatrix)
{
    mViewMatrix = viewMatrix;
}

void GLWidget::setAspectRatio(double aspectRatio) {
    mAspectRatio = aspectRatio;
}

void GLWidget::addObject(int id, SceneObject so, bool /*selected*/)
{
    mObjects[id] = so;
}

void GLWidget::clear()
{
    mObjects.clear();
}

void GLWidget::zoomIn()
{
    if (mAnimationTimer.isActive()) {
        mAnimationTimer.stop();
        m_fScale = mEndScale;
        update();
    }
    mAnimationLengthms = 500;
    mStartScale = m_fScale;
    mEndScale = m_fScale * 2;
    mElapsedTimer.start();
    mAnimationTimer.start(10);
}

void GLWidget::zoomOut()
{
    if (mAnimationTimer.isActive()) {
        mAnimationTimer.stop();
        m_fScale = mEndScale;
        update();
    }

    mAnimationLengthms = 500;
    mStartScale = m_fScale;
    mEndScale = m_fScale / 2.0;
    mElapsedTimer.start();
    mAnimationTimer.start(10);
}

void GLWidget::setScreenShot(QImage img)
{
    mScreenShot = img;
}

void GLWidget::setSelection(int id)
{
    mSelectedIds.clear();
    mSelectedIds.push_back(id);
    mSelectionIndex=0;
    update();
}

void GLWidget::animate()
{
    float step = mEndScale - mStartScale;
    qint64 elapsedTimems = mElapsedTimer.nsecsElapsed()/1000000;
    float scalefac = ((float)(elapsedTimems)/(float)mAnimationLengthms);
    m_fScale = mStartScale + scalefac*step;
    if (mElapsedTimer.hasExpired(mAnimationLengthms)) {
        m_fScale = mEndScale;
        mAnimationTimer.stop();
    }
    update();
}

void GLWidget::drawRect()
{
    glBindTexture(GL_TEXTURE_2D, m_uiTexture);
    GLfloat afVertices[] = {
        -0.5, 0.5, 0.5, 0.5,-0.5,0.5,-0.5,-0.5,0.5,
        0.5, -0.5, 0.5, -0.5,0.5,0.5,0.5,0.5,0.5
    };
    program.setAttributeArray(vertexAttr, afVertices, 3);

    GLfloat afTexCoord[] = {
        0.0f,0.0f, 1.0f,1.0f, 0.0f,1.0f,
        1.0f,1.0f, 0.0f,0.0f, 1.0f,0.0f
    };
    program.setAttributeArray(texCoordAttr, afTexCoord, 2);

    GLfloat afNormals[] = {

        0,0,-1, 0,0,-1, 0,0,-1,
        0,0,-1, 0,0,-1, 0,0,-1
    };
    program.setAttributeArray(normalAttr, afNormals, 3);

    program.setUniformValue(textureUniform, 0);    // use texture unit 0

    program.enableAttributeArray(vertexAttr);
    program.enableAttributeArray(normalAttr);
    program.enableAttributeArray(texCoordAttr);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    program.disableAttributeArray(vertexAttr);
    program.disableAttributeArray(normalAttr);
    program.disableAttributeArray(texCoordAttr);
}

void GLWidget::initializeGL ()
{
    glClearColor(0.1f, 0.1f, 0.2f, 1.0f);

    glGenTextures(1, &m_uiTexture);

    QGLShader *vshader = new QGLShader(QGLShader::Vertex);
    vshader->compileSourceFile(":/stagehand/shader.vsh");

    QGLShader *fshader = new QGLShader(QGLShader::Fragment);
    fshader->compileSourceFile(":/stagehand/shader.fsh");

    program.addShader(vshader);
    program.addShader(fshader);
    program.link();

    vertexAttr = program.attributeLocation("vertex");
    normalAttr = program.attributeLocation("normal");
    texCoordAttr = program.attributeLocation("texCoord");
    matrixUniform = program.uniformLocation("matrix");
    textureUniform = program.uniformLocation("tex");
    selectedUniform = program.uniformLocation("selected");
    screenShotUniform = program.uniformLocation("screenshot");
    drawTextureUniform = program.uniformLocation("drawTexture");
    xthresholdUniform = program.uniformLocation("xthreshold");
    ythresholdUniform = program.uniformLocation("ythreshold");

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    m_fAngle = 0;
}

void GLWidget::paintGL()
{
    QPainter painter;
    painter.begin(this);

    painter.beginNativePainting();
    glClearColor(0.1f, 0.1f, 0.2f, 1.0f);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    glFrontFace(GL_CW);
    glCullFace(GL_FRONT);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

    if (mObjects.size()>0) {

        m_uiTexture = bindTexture(mScreenShot);
        program.bind();
        mModelView = mProjectionMatrix * mViewMatrix;
        mModelView.translate(mTranslateX + mDragX ,mTranslateY + mDragY ,0);
        mModelView.scale(mAspectRatio, 1.0, 1.0);
        mModelView.scale(m_fScale,m_fScale,1.0);

        int selectionId = 0;
        if (mSelectionIndex < mSelectedIds.size()) {
            selectionId = mSelectedIds[mSelectionIndex];
        }

        std::map<int, SceneObject>::iterator iter;
        for (iter = mObjects.begin();iter != mObjects.end();iter++) {
            SceneObject so = (*iter).second;
            QMatrix4x4 objectMatrix = so.mWorldMatrix;

            QVector3D size = so.mSize;
            objectMatrix.scale(size);
            objectMatrix = mModelView * objectMatrix;
            objectMatrix.scale(1.0f, 1.0f, 0.05f);

            QVector3D tl(-0.5, 0.5,0.0);
            QVector3D br(0.5, -0.5,0.0);
            tl = objectMatrix*tl;
            br = objectMatrix*br;
            float xpixels = (float)width() * (br.x()-tl.x())/2.0;
            float xthreshold = 1.0/xpixels;
            float ypixels = (float)height() * (br.y()-tl.y())/2.0;
            float ythreshold = 1.0/ypixels;

            program.setUniformValue(drawTextureUniform, mShowScreenShot && (*iter).first == 1);
            program.setUniformValue(matrixUniform, objectMatrix);
            program.setUniformValue(selectedUniform, (*iter).first == selectionId);
            program.setUniformValue(screenShotUniform, mShowScreenShot);
            program.setUniformValue(xthresholdUniform, xthreshold);
            program.setUniformValue(ythresholdUniform, ythreshold);

            drawRect();

        }
        program.release();
    } else {
        drawLogo();
    }

    glDisable(GL_CULL_FACE);

    painter.endNativePainting();

    painter.end();

    swapBuffers();
}

void GLWidget::drawLogo() {
    QMatrix4x4 objectMatrix;
    float ratio = (float)mLogo.height()/(float)mLogo.width();
    objectMatrix.scale(1.0f, -ratio, 1.0f);
    m_uiTexture = bindTexture(mLogo);
    program.bind();
    program.setUniformValue(drawTextureUniform, true);
    program.setUniformValue(matrixUniform, objectMatrix);
    program.setUniformValue(selectedUniform, false);
    program.setUniformValue(screenShotUniform, true);
    program.setUniformValue(xthresholdUniform, 0.2f);
    program.setUniformValue(ythresholdUniform, 0.2f);

    drawRect();
    program.release();
}

void GLWidget::mouseMoveEvent(QMouseEvent* event) {
    QPoint currpoint = event->pos();
    if (mDragging) {
        currpoint -= mStartPoint;
        mDragX = currpoint.x();
        mDragY = currpoint.y();
        update();
    } else {
        // assume that the first node has the screen size

       if (mObjects.size()>0) {
           float x = (float)event->pos().x()/(float)width()*2.0f -1.0f;
           float y = (float)event->pos().y()/(float)height()*-2.0f + 1.0f;
           SceneObject so = mObjects[1];

           QMatrix4x4 objectMatrix = so.mWorldMatrix;

           QVector3D size = so.mSize;
           objectMatrix.scale(size);
           objectMatrix = mModelView * objectMatrix;
           objectMatrix.scale(1.0f, 1.0f, 0.05f);
           QVector3D tl(-0.5, 0.5,0.0);
           QVector3D br(0.5, -0.5,0.0);
           tl = objectMatrix*tl;
           br = objectMatrix*br;
           if (x >= tl.x() && y >= tl.y() &&
                   x <= br.x() && y <= br.y()) {
               x-= tl.x();
               y-= tl.y();
               x /= br.x() - tl.x();
               y /= br.y() - tl.y();
               y = 1 - y; //flip axis
               mousePosition((int)(x*size.x()), (int)(y*size.y()));
           } else {
               mousePosition(-1, -1);
           }

        }

    }
}

void GLWidget::mousePressEvent(QMouseEvent *eventPress){
    mStartPoint = eventPress->pos();
    mDragging = true;
}

void GLWidget::mouseReleaseEvent(QMouseEvent *releaseEvent){
    mTranslateX += mDragX;
    mTranslateY += mDragY;
    mDragX = mDragY = 0;

    if (releaseEvent->pos() == mStartPoint) {
        QPoint pos = releaseEvent->pos();
        float x = (float)pos.x()/(float)width()*2.0f -1.0f;
        float y = (float)pos.y()/(float)height()*-2.0f + 1.0f;
        select(x,y);
    }
    mDragging = false;
    update();
}

void GLWidget::select(float x, float y) {
    std::vector<int> ids;
    std::map<int, SceneObject>::iterator iter;
    for (iter = mObjects.begin();iter != mObjects.end();iter++) {
        SceneObject so = (*iter).second;
        QMatrix4x4 objectMatrix = so.mWorldMatrix;

        QVector3D size = so.mSize;
        objectMatrix.scale(size);
        objectMatrix = mModelView * objectMatrix;
        objectMatrix.scale(1.0f, 1.0f, 0.05f);
        QVector3D tl(-0.5, 0.5,0.0);
        QVector3D br(0.5, -0.5,0.0);
        tl = objectMatrix*tl;
        br = objectMatrix*br;
        if (x >= tl.x() && y >= tl.y() &&
            x <= br.x() && y <= br.y()) {
            ids.insert(ids.begin(), (*iter).first);
        }

    }
    bool is_equal = false;
    if ( ids.size() > 0 && ids.size() == mSelectedIds.size() )
        is_equal = std::equal ( ids.begin(), ids.end(), mSelectedIds.begin() );

    if (is_equal) {
        mSelectionIndex++;
        mSelectionIndex %= mSelectedIds.size();
    } else {
        mSelectedIds = ids;
        mSelectionIndex = 0;
    }

    if (mSelectionIndex < mSelectedIds.size()) {
        emit selectedId(mSelectedIds[mSelectionIndex]);
    }
}
<commit_msg>Correctly find root node, even when it has a different index from 1<commit_after>/*
 * Copyright (c) 2014 Gamoeba Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "glwidget.h"
#include <QPainter>
#include <QPaintEngine>
#include <QMouseEvent>
#include <math.h>
#include <map>

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(parent)
{
    qtLogo = true;
    m_fScale = 1.0;
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setAutoBufferSwap(false);

    mTranslateX = 0;
    mTranslateY = 0;
    mDragX = 0;
    mDragY = 0;
    mSelectionIndex=0;
    mShowScreenShot = false;
    mDragging = false;

    connect(&mAnimationTimer,SIGNAL(timeout()),SLOT(animate()));
    setMouseTracking(true);

    mLogo = QPixmap(":/stagehand/splash.png");

}

GLWidget::~GLWidget()
{
}

void GLWidget::setProjectionMatrix(QMatrix4x4 projMatrix)
{
    mProjectionMatrix = projMatrix;
}

void GLWidget::setViewMatrix(QMatrix4x4 viewMatrix)
{
    mViewMatrix = viewMatrix;
}

void GLWidget::setAspectRatio(double aspectRatio) {
    mAspectRatio = aspectRatio;
}

void GLWidget::addObject(int id, SceneObject so, bool /*selected*/)
{
    mObjects[id] = so;
}

void GLWidget::clear()
{
    mObjects.clear();
}

void GLWidget::zoomIn()
{
    if (mAnimationTimer.isActive()) {
        mAnimationTimer.stop();
        m_fScale = mEndScale;
        update();
    }
    mAnimationLengthms = 500;
    mStartScale = m_fScale;
    mEndScale = m_fScale * 2;
    mElapsedTimer.start();
    mAnimationTimer.start(10);
}

void GLWidget::zoomOut()
{
    if (mAnimationTimer.isActive()) {
        mAnimationTimer.stop();
        m_fScale = mEndScale;
        update();
    }

    mAnimationLengthms = 500;
    mStartScale = m_fScale;
    mEndScale = m_fScale / 2.0;
    mElapsedTimer.start();
    mAnimationTimer.start(10);
}

void GLWidget::setScreenShot(QImage img)
{
    mScreenShot = img;
}

void GLWidget::setSelection(int id)
{
    mSelectedIds.clear();
    mSelectedIds.push_back(id);
    mSelectionIndex=0;
    update();
}

void GLWidget::animate()
{
    float step = mEndScale - mStartScale;
    qint64 elapsedTimems = mElapsedTimer.nsecsElapsed()/1000000;
    float scalefac = ((float)(elapsedTimems)/(float)mAnimationLengthms);
    m_fScale = mStartScale + scalefac*step;
    if (mElapsedTimer.hasExpired(mAnimationLengthms)) {
        m_fScale = mEndScale;
        mAnimationTimer.stop();
    }
    update();
}

void GLWidget::drawRect()
{
    glBindTexture(GL_TEXTURE_2D, m_uiTexture);
    GLfloat afVertices[] = {
        -0.5, 0.5, 0.5, 0.5,-0.5,0.5,-0.5,-0.5,0.5,
        0.5, -0.5, 0.5, -0.5,0.5,0.5,0.5,0.5,0.5
    };
    program.setAttributeArray(vertexAttr, afVertices, 3);

    GLfloat afTexCoord[] = {
        0.0f,0.0f, 1.0f,1.0f, 0.0f,1.0f,
        1.0f,1.0f, 0.0f,0.0f, 1.0f,0.0f
    };
    program.setAttributeArray(texCoordAttr, afTexCoord, 2);

    GLfloat afNormals[] = {

        0,0,-1, 0,0,-1, 0,0,-1,
        0,0,-1, 0,0,-1, 0,0,-1
    };
    program.setAttributeArray(normalAttr, afNormals, 3);

    program.setUniformValue(textureUniform, 0);    // use texture unit 0

    program.enableAttributeArray(vertexAttr);
    program.enableAttributeArray(normalAttr);
    program.enableAttributeArray(texCoordAttr);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    program.disableAttributeArray(vertexAttr);
    program.disableAttributeArray(normalAttr);
    program.disableAttributeArray(texCoordAttr);
}

void GLWidget::initializeGL ()
{
    glClearColor(0.1f, 0.1f, 0.2f, 1.0f);

    glGenTextures(1, &m_uiTexture);

    QGLShader *vshader = new QGLShader(QGLShader::Vertex);
    vshader->compileSourceFile(":/stagehand/shader.vsh");

    QGLShader *fshader = new QGLShader(QGLShader::Fragment);
    fshader->compileSourceFile(":/stagehand/shader.fsh");

    program.addShader(vshader);
    program.addShader(fshader);
    program.link();

    vertexAttr = program.attributeLocation("vertex");
    normalAttr = program.attributeLocation("normal");
    texCoordAttr = program.attributeLocation("texCoord");
    matrixUniform = program.uniformLocation("matrix");
    textureUniform = program.uniformLocation("tex");
    selectedUniform = program.uniformLocation("selected");
    screenShotUniform = program.uniformLocation("screenshot");
    drawTextureUniform = program.uniformLocation("drawTexture");
    xthresholdUniform = program.uniformLocation("xthreshold");
    ythresholdUniform = program.uniformLocation("ythreshold");

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    m_fAngle = 0;
}

void GLWidget::paintGL()
{
    QPainter painter;
    painter.begin(this);

    painter.beginNativePainting();
    glClearColor(0.1f, 0.1f, 0.2f, 1.0f);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    glFrontFace(GL_CW);
    glCullFace(GL_FRONT);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

    if (mObjects.size()>0) {

        m_uiTexture = bindTexture(mScreenShot);
        program.bind();
        mModelView = mProjectionMatrix * mViewMatrix;
        mModelView.translate(mTranslateX + mDragX ,mTranslateY + mDragY ,0);
        mModelView.scale(mAspectRatio, 1.0, 1.0);
        mModelView.scale(m_fScale,m_fScale,1.0);

        int selectionId = 0;
        if (mSelectionIndex < mSelectedIds.size()) {
            selectionId = mSelectedIds[mSelectionIndex];
        }

        std::map<int, SceneObject>::iterator iter;
        for (iter = mObjects.begin();iter != mObjects.end();iter++) {
            SceneObject so = (*iter).second;
            QMatrix4x4 objectMatrix = so.mWorldMatrix;

            QVector3D size = so.mSize;
            objectMatrix.scale(size);
            objectMatrix = mModelView * objectMatrix;
            objectMatrix.scale(1.0f, 1.0f, 0.05f);

            QVector3D tl(-0.5, 0.5,0.0);
            QVector3D br(0.5, -0.5,0.0);
            tl = objectMatrix*tl;
            br = objectMatrix*br;
            float xpixels = (float)width() * (br.x()-tl.x())/2.0;
            float xthreshold = 1.0/xpixels;
            float ypixels = (float)height() * (br.y()-tl.y())/2.0;
            float ythreshold = 1.0/ypixels;

            program.setUniformValue(drawTextureUniform, mShowScreenShot && (*iter).first == 1);
            program.setUniformValue(matrixUniform, objectMatrix);
            program.setUniformValue(selectedUniform, (*iter).first == selectionId);
            program.setUniformValue(screenShotUniform, mShowScreenShot);
            program.setUniformValue(xthresholdUniform, xthreshold);
            program.setUniformValue(ythresholdUniform, ythreshold);

            drawRect();

        }
        program.release();
    } else {
        drawLogo();
    }

    glDisable(GL_CULL_FACE);

    painter.endNativePainting();

    painter.end();

    swapBuffers();
}

void GLWidget::drawLogo() {
    QMatrix4x4 objectMatrix;
    float ratio = (float)mLogo.height()/(float)mLogo.width();
    objectMatrix.scale(1.0f, -ratio, 1.0f);
    m_uiTexture = bindTexture(mLogo);
    program.bind();
    program.setUniformValue(drawTextureUniform, true);
    program.setUniformValue(matrixUniform, objectMatrix);
    program.setUniformValue(selectedUniform, false);
    program.setUniformValue(screenShotUniform, true);
    program.setUniformValue(xthresholdUniform, 0.2f);
    program.setUniformValue(ythresholdUniform, 0.2f);

    drawRect();
    program.release();
}

void GLWidget::mouseMoveEvent(QMouseEvent* event) {
    QPoint currpoint = event->pos();
    if (mDragging) {
        currpoint -= mStartPoint;
        mDragX = currpoint.x();
        mDragY = currpoint.y();
        update();
    } else {
        // assume that the first node has the screen size

       if (mObjects.size()>0) {
           float x = (float)event->pos().x()/(float)width()*2.0f -1.0f;
           float y = (float)event->pos().y()/(float)height()*-2.0f + 1.0f;

           SceneObject so = mObjects.begin()->second;

           QMatrix4x4 objectMatrix = so.mWorldMatrix;

           QVector3D size = so.mSize;
           objectMatrix.scale(size);
           objectMatrix = mModelView * objectMatrix;
           objectMatrix.scale(1.0f, 1.0f, 0.05f);
           QVector3D tl(-0.5, 0.5,0.0);
           QVector3D br(0.5, -0.5,0.0);
           tl = objectMatrix*tl;
           br = objectMatrix*br;
           if (x >= tl.x() && y >= tl.y() &&
                   x <= br.x() && y <= br.y()) {
               x-= tl.x();
               y-= tl.y();
               x /= br.x() - tl.x();
               y /= br.y() - tl.y();
               y = 1 - y; //flip axis
               mousePosition((int)(x*size.x()), (int)(y*size.y()));
           } else {
               mousePosition(-1, -1);
           }

        }

    }
}

void GLWidget::mousePressEvent(QMouseEvent *eventPress){
    mStartPoint = eventPress->pos();
    mDragging = true;
}

void GLWidget::mouseReleaseEvent(QMouseEvent *releaseEvent){
    mTranslateX += mDragX;
    mTranslateY += mDragY;
    mDragX = mDragY = 0;

    if (releaseEvent->pos() == mStartPoint) {
        QPoint pos = releaseEvent->pos();
        float x = (float)pos.x()/(float)width()*2.0f -1.0f;
        float y = (float)pos.y()/(float)height()*-2.0f + 1.0f;
        select(x,y);
    }
    mDragging = false;
    update();
}

void GLWidget::select(float x, float y) {
    std::vector<int> ids;
    std::map<int, SceneObject>::iterator iter;
    for (iter = mObjects.begin();iter != mObjects.end();iter++) {
        SceneObject so = (*iter).second;
        QMatrix4x4 objectMatrix = so.mWorldMatrix;

        QVector3D size = so.mSize;
        objectMatrix.scale(size);
        objectMatrix = mModelView * objectMatrix;
        objectMatrix.scale(1.0f, 1.0f, 0.05f);
        QVector3D tl(-0.5, 0.5,0.0);
        QVector3D br(0.5, -0.5,0.0);
        tl = objectMatrix*tl;
        br = objectMatrix*br;
        if (x >= tl.x() && y >= tl.y() &&
            x <= br.x() && y <= br.y()) {
            ids.insert(ids.begin(), (*iter).first);
        }

    }
    bool is_equal = false;
    if ( ids.size() > 0 && ids.size() == mSelectedIds.size() )
        is_equal = std::equal ( ids.begin(), ids.end(), mSelectedIds.begin() );

    if (is_equal) {
        mSelectionIndex++;
        mSelectionIndex %= mSelectedIds.size();
    } else {
        mSelectedIds = ids;
        mSelectionIndex = 0;
    }

    if (mSelectionIndex < mSelectedIds.size()) {
        emit selectedId(mSelectedIds[mSelectionIndex]);
    }
}
<|endoftext|>


<commit_before>
#pragma once

#include "numerics/quadrature.hpp"

#include <memory>
#include <vector>

#include "base/bits.hpp"
#include "geometry/hilbert.hpp"
#include "numerics/fast_fourier_transform.hpp"
#include "numerics/gauss_legendre_weights.mathematica.h"
#include "numerics/legendre_roots.mathematica.h"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace numerics {
namespace quadrature {
namespace internal_quadrature {

using base::BitReversedIncrement;
using base::FloorLog2;
using geometry::Hilbert;
using quantities::Angle;
using quantities::Cos;
using quantities::Difference;
using quantities::si::Radian;

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument> Gauss(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    double const* const nodes,
    double const* const weights) {
  Difference<Argument> half_width = (upper_bound - lower_bound) / 2;
  std::invoke_result_t<Function, Argument> result{};
  for (int i = 0; i < points; ++i) {
    Argument const scaled_node = lower_bound + half_width * (nodes[i] + 1);
    // TODO(phl): Consider compensated summation.
    result += weights[i] * f(scaled_node);
  }
  return result * half_width;
}

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument> GaussLegendre(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound) {
  static_assert(points < LegendreRoots.size,
                "No table for Gauss-Legendre with the chosen number of points");
  return Gauss<points>(f,
                       lower_bound,
                       upper_bound,
                       LegendreRoots[points],
                       GaussLegendreWeights[points]);
}

// Our automatic Cleshaw-Curtis implementation doubles the number of points
// repeatedly until it reaches a suitable exit criterion.  Naïvely evaluating
// the function N times for each iteration would be wasteful.  Assume that we
// have already evaluated the function at 0/2 and 1/2 (that is, s = 0 and 1 for
// N = 2), we would evaluate it again at 0/4 and 2/4 for N = 4, and then proceed
// with evaluations at 1/4 and 3/4.  Overall, we would do roughly twice the
// work.
// Therefore, we cache the past evaluations.  However, we do not want to use a
// map and we do not want to do insertion in a vector, say, to squeeze 1/4
// between 0/2 and 1/2.  So we append the result of evaluations to the cache
// vector as we perform them.  To fill the cache for N points, we recursively
// fill it for N/2 points (which yields all the values at s/N for s even) and
// then we append the values at s/N for s odd.  The order of the second part
// matters.  It is done by taking the indices of the first part (covering
// [0/N, (N/2-1)/N[) in bit-reversed order and for each index s appending the
// value at (2 s + 1)/N.  This ensures that the entire array follows
// bit-reversed ordering.
// There is an extra wart: we need the value at N/N, but it does not fit nicely
// in the bit-reversed ordering.  So we store it at position 0 in the cache, and
// the regular cache starts at index 1.
// Clients are expected to reserve (at least) points entries in the cache vector
// for efficient heap allocation.
template<int points, typename Argument, typename Function>
void FillClenshawCurtisCache(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed) {
  // If we identify [lower_bound, upper_bound] with [-1, 1],
  // f_cos_N⁻¹π_bit_reversed contains f(cos πs/N) in bit-reversed order of s.
  // We use a discrete Fourier transform rather than a cosine transform, see
  // [Gen72c], equation (3).

  // The cache already has all the data we need.
  if (f_cos_N⁻¹π_bit_reversed.size() >= points) {
    return;
  }

  constexpr int N = points - 1;
  static_assert(N >= 1);
  constexpr int log2_N = FloorLog2(N);
  static_assert(N == 1 << log2_N);

  Difference<Argument> const half_width = (upper_bound - lower_bound) / 2;
  constexpr Angle N⁻¹π = π * Radian / N;

  if constexpr (N == 1) {
    DCHECK(f_cos_N⁻¹π_bit_reversed.empty());
    // See above for the magic entry at index 0.  The entry at index 1 is a bona
    // fide entry which will be used by the recursive calls.
    f_cos_N⁻¹π_bit_reversed.push_back(f(lower_bound));  // s = N.
    f_cos_N⁻¹π_bit_reversed.push_back(f(upper_bound));  // s = 0.
  } else {
    // Fill the first half of the cache, corresponding to s even for this value
    // of N.
    FillClenshawCurtisCache<N / 2 + 1>(f,
                                       lower_bound, upper_bound,
                                       f_cos_N⁻¹π_bit_reversed);
    // N/2 evaluations for f(cos πs/N) with s odd.  Note the need to preserve
    // bit-reversed ordering.
    int reverse = 0;
    for (int evaluations = 0;
         evaluations < N / 2;
         ++evaluations, reverse = BitReversedIncrement(reverse, log2_N - 1)) {
      int const s = 2 * reverse + 1;
      f_cos_N⁻¹π_bit_reversed.push_back(
          f(lower_bound + half_width * (1 + Cos(N⁻¹π * s))));
    }
  }
}

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument>
AutomaticClenshawCurtisImplementation(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::optional<double> const max_relative_error,
    std::optional<int> const max_points,
    Primitive<std::invoke_result_t<Function, Argument>, Argument> const
        previous_estimate,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed) {
  using Result = Primitive<std::invoke_result_t<Function, Argument>, Argument>;

  Result const estimate =
      ClenshawCurtisImplementation<points>(
          f, lower_bound, upper_bound, f_cos_N⁻¹π_bit_reversed);

  // This is the naïve estimate mentioned in [Gen72b], p. 339.
  auto const absolute_error_estimate =
      Hilbert<Result>::Norm(previous_estimate - estimate);

  if ((!max_relative_error.has_value() ||
       absolute_error_estimate >
           max_relative_error.value() * Hilbert<Result>::Norm(estimate)) &&
      (!max_points.has_value() || points <= max_points.value())) {
    if constexpr (points > 1 << 24) {
      LOG(FATAL) << "Too many refinements while integrating from "
                 << lower_bound << " to " << upper_bound;
    } else {
      f_cos_N⁻¹π_bit_reversed.reserve(2 * points - 1);
      return AutomaticClenshawCurtisImplementation<2 * points - 1>(
          f,
          lower_bound, upper_bound,
          max_relative_error, max_points,
          estimate,
          f_cos_N⁻¹π_bit_reversed);
    }
  }
  return estimate;
}

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument>
ClenshawCurtisImplementation(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed) {
  // We follow the notation from [Gen72b] and [Gen72c].
  using Value = std::invoke_result_t<Function, Argument>;

  constexpr int N = points - 1;
  constexpr int log2_N = FloorLog2(N);

  Difference<Argument> const half_width = (upper_bound - lower_bound) / 2;
  constexpr Angle N⁻¹π = π * Radian / N;

  FillClenshawCurtisCache<points>(
      f, lower_bound, upper_bound, f_cos_N⁻¹π_bit_reversed);

  // TODO(phl): If might be possible to avoid copies since
  // f_cos_N⁻¹π_bit_reversed is tantalizing close to the order needed for the
  // FFT.
  std::vector<Value> f_cos_N⁻¹π;
  f_cos_N⁻¹π.resize(2 * N);
  // An index in f_cos_N⁻¹π in the order described by [Gen72b] and [Gen72c].
  int s = 0;
  // An index in f_cos_N⁻¹π_bit_reversed, corresponding to the order in which
  // the values were put in the cache.  Note that entry 0 is special and holds
  // the value corresponding to s = N.
  for (int bit_reversed_s = 1;
       bit_reversed_s <= N;
       ++bit_reversed_s, s = BitReversedIncrement(s, log2_N)) {
    f_cos_N⁻¹π[s] = f_cos_N⁻¹π_bit_reversed[bit_reversed_s];
    if (s > 0) {
      f_cos_N⁻¹π[2 * N - s] = f_cos_N⁻¹π[s];  // [Gen72c] (5).
    }
  }
  f_cos_N⁻¹π[N] = f_cos_N⁻¹π_bit_reversed[0];

  auto const fft = std::make_unique<FastFourierTransform<Value, Angle, 2 * N>>(
      f_cos_N⁻¹π, N⁻¹π);
  auto const& a = *fft;

  // [Gen72b] equation (7), factoring out the division by N.
  Value Σʺ{};
  for (std::int64_t n = 0; n <= N; n += 2) {
    // The notation g is from [OLBC10], 3.5.17.
    int const gₙ = n == 0 || n == N ? 1 : 2;
    Σʺ += a[n].real_part() * gₙ / (1 - n * n);
  }
  Σʺ /= N;

  return Σʺ * half_width;
}

template<int initial_points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument>
AutomaticClenshawCurtis(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::optional<double> const max_relative_error,
    std::optional<int> const max_points) {
  using Result = Primitive<std::invoke_result_t<Function, Argument>, Argument>;
  using Value = std::invoke_result_t<Function, Argument>;
  std::vector<Value> f_cos_N⁻¹π_bit_reversed;
  f_cos_N⁻¹π_bit_reversed.reserve(2 * initial_points - 1);
  Result const estimate = ClenshawCurtisImplementation<initial_points>(
      f, lower_bound, upper_bound, f_cos_N⁻¹π_bit_reversed);
  return AutomaticClenshawCurtisImplementation<2 * initial_points - 1>(
      f,
      lower_bound, upper_bound,
      max_relative_error, max_points,
      estimate,
      f_cos_N⁻¹π_bit_reversed);
}

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument> ClenshawCurtis(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound) {
  using Value = std::invoke_result_t<Function, Argument>;
  std::vector<Value> f_cos_N⁻¹π_bit_reversed;
  f_cos_N⁻¹π_bit_reversed.reserve(points);
  return ClenshawCurtisImplementation<points>(
      f, lower_bound, upper_bound, f_cos_N⁻¹π_bit_reversed);
}

template<typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument> Midpoint(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    int const intervals) {
  Difference<Argument> const h = (upper_bound - lower_bound) / intervals;
  Primitive<std::invoke_result_t<Function, Argument>, Argument> result{};
  for (int i = 0; i < intervals; ++i) {
    result += f(lower_bound + (i + 0.5) * h) * h;
  }
  return result;
}

}  // namespace internal_quadrature
}  // namespace quadrature
}  // namespace numerics
}  // namespace principia
<commit_msg>Declare and reorder functions.<commit_after>
#pragma once

#include "numerics/quadrature.hpp"

#include <memory>
#include <vector>

#include "base/bits.hpp"
#include "geometry/hilbert.hpp"
#include "numerics/fast_fourier_transform.hpp"
#include "numerics/gauss_legendre_weights.mathematica.h"
#include "numerics/legendre_roots.mathematica.h"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace numerics {
namespace quadrature {
namespace internal_quadrature {

using base::BitReversedIncrement;
using base::FloorLog2;
using geometry::Hilbert;
using quantities::Angle;
using quantities::Cos;
using quantities::Difference;
using quantities::si::Radian;

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument> Gauss(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    double const* const nodes,
    double const* const weights) {
  Difference<Argument> half_width = (upper_bound - lower_bound) / 2;
  std::invoke_result_t<Function, Argument> result{};
  for (int i = 0; i < points; ++i) {
    Argument const scaled_node = lower_bound + half_width * (nodes[i] + 1);
    // TODO(phl): Consider compensated summation.
    result += weights[i] * f(scaled_node);
  }
  return result * half_width;
}

template<int points, typename Argument, typename Function>
void FillClenshawCurtisCache(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed);

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument>
AutomaticClenshawCurtisImplementation(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::optional<double> const max_relative_error,
    std::optional<int> const max_points,
    Primitive<std::invoke_result_t<Function, Argument>, Argument> const
        previous_estimate,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed);

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument>
ClenshawCurtisImplementation(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed);

// Our automatic Cleshaw-Curtis implementation doubles the number of points
// repeatedly until it reaches a suitable exit criterion.  Naïvely evaluating
// the function N times for each iteration would be wasteful.  Assume that we
// have already evaluated the function at 0/2 and 1/2 (that is, s = 0 and 1 for
// N = 2), we would evaluate it again at 0/4 and 2/4 for N = 4, and then proceed
// with evaluations at 1/4 and 3/4.  Overall, we would do roughly twice the
// work.
// Therefore, we cache the past evaluations.  However, we do not want to use a
// map and we do not want to do insertion in a vector, say, to squeeze 1/4
// between 0/2 and 1/2.  So we append the result of evaluations to the cache
// vector as we perform them.  To fill the cache for N points, we recursively
// fill it for N/2 points (which yields all the values at s/N for s even) and
// then we append the values at s/N for s odd.  The order of the second part
// matters.  It is done by taking the indices of the first part (covering
// [0/N, (N/2-1)/N[) in bit-reversed order and for each index s appending the
// value at (2 s + 1)/N.  This ensures that the entire array follows
// bit-reversed ordering.
// There is an extra wart: we need the value at N/N, but it does not fit nicely
// in the bit-reversed ordering.  So we store it at position 0 in the cache, and
// the regular cache starts at index 1.
// Clients are expected to reserve (at least) points entries in the cache vector
// for efficient heap allocation.
template<int points, typename Argument, typename Function>
void FillClenshawCurtisCache(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed) {
  // If we identify [lower_bound, upper_bound] with [-1, 1],
  // f_cos_N⁻¹π_bit_reversed contains f(cos πs/N) in bit-reversed order of s.
  // We use a discrete Fourier transform rather than a cosine transform, see
  // [Gen72c], equation (3).

  // The cache already has all the data we need.
  if (f_cos_N⁻¹π_bit_reversed.size() >= points) {
    return;
  }

  constexpr int N = points - 1;
  static_assert(N >= 1);
  constexpr int log2_N = FloorLog2(N);
  static_assert(N == 1 << log2_N);

  Difference<Argument> const half_width = (upper_bound - lower_bound) / 2;
  constexpr Angle N⁻¹π = π * Radian / N;

  if constexpr (N == 1) {
    DCHECK(f_cos_N⁻¹π_bit_reversed.empty());
    // See above for the magic entry at index 0.  The entry at index 1 is a bona
    // fide entry which will be used by the recursive calls.
    f_cos_N⁻¹π_bit_reversed.push_back(f(lower_bound));  // s = N.
    f_cos_N⁻¹π_bit_reversed.push_back(f(upper_bound));  // s = 0.
  } else {
    // Fill the first half of the cache, corresponding to s even for this value
    // of N.
    FillClenshawCurtisCache<N / 2 + 1>(f,
                                       lower_bound, upper_bound,
                                       f_cos_N⁻¹π_bit_reversed);
    // N/2 evaluations for f(cos πs/N) with s odd.  Note the need to preserve
    // bit-reversed ordering.
    int reverse = 0;
    for (int evaluations = 0;
         evaluations < N / 2;
         ++evaluations, reverse = BitReversedIncrement(reverse, log2_N - 1)) {
      int const s = 2 * reverse + 1;
      f_cos_N⁻¹π_bit_reversed.push_back(
          f(lower_bound + half_width * (1 + Cos(N⁻¹π * s))));
    }
  }
}

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument>
AutomaticClenshawCurtisImplementation(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::optional<double> const max_relative_error,
    std::optional<int> const max_points,
    Primitive<std::invoke_result_t<Function, Argument>, Argument> const
        previous_estimate,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed) {
  using Result = Primitive<std::invoke_result_t<Function, Argument>, Argument>;

  Result const estimate =
      ClenshawCurtisImplementation<points>(
          f, lower_bound, upper_bound, f_cos_N⁻¹π_bit_reversed);

  // This is the naïve estimate mentioned in [Gen72b], p. 339.
  auto const absolute_error_estimate =
      Hilbert<Result>::Norm(previous_estimate - estimate);

  if ((!max_relative_error.has_value() ||
       absolute_error_estimate >
           max_relative_error.value() * Hilbert<Result>::Norm(estimate)) &&
      (!max_points.has_value() || points <= max_points.value())) {
    if constexpr (points > 1 << 24) {
      LOG(FATAL) << "Too many refinements while integrating from "
                 << lower_bound << " to " << upper_bound;
    } else {
      f_cos_N⁻¹π_bit_reversed.reserve(2 * points - 1);
      return AutomaticClenshawCurtisImplementation<2 * points - 1>(
          f,
          lower_bound, upper_bound,
          max_relative_error, max_points,
          estimate,
          f_cos_N⁻¹π_bit_reversed);
    }
  }
  return estimate;
}

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument>
ClenshawCurtisImplementation(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::vector<std::invoke_result_t<Function, Argument>>&
        f_cos_N⁻¹π_bit_reversed) {
  // We follow the notation from [Gen72b] and [Gen72c].
  using Value = std::invoke_result_t<Function, Argument>;

  constexpr int N = points - 1;
  constexpr int log2_N = FloorLog2(N);

  Difference<Argument> const half_width = (upper_bound - lower_bound) / 2;
  constexpr Angle N⁻¹π = π * Radian / N;

  FillClenshawCurtisCache<points>(
      f, lower_bound, upper_bound, f_cos_N⁻¹π_bit_reversed);

  // TODO(phl): If might be possible to avoid copies since
  // f_cos_N⁻¹π_bit_reversed is tantalizing close to the order needed for the
  // FFT.
  std::vector<Value> f_cos_N⁻¹π;
  f_cos_N⁻¹π.resize(2 * N);
  // An index in f_cos_N⁻¹π in the order described by [Gen72b] and [Gen72c].
  int s = 0;
  // An index in f_cos_N⁻¹π_bit_reversed, corresponding to the order in which
  // the values were put in the cache.  Note that entry 0 is special and holds
  // the value corresponding to s = N.
  for (int bit_reversed_s = 1;
       bit_reversed_s <= N;
       ++bit_reversed_s, s = BitReversedIncrement(s, log2_N)) {
    f_cos_N⁻¹π[s] = f_cos_N⁻¹π_bit_reversed[bit_reversed_s];
    if (s > 0) {
      f_cos_N⁻¹π[2 * N - s] = f_cos_N⁻¹π[s];  // [Gen72c] (5).
    }
  }
  f_cos_N⁻¹π[N] = f_cos_N⁻¹π_bit_reversed[0];

  auto const fft = std::make_unique<FastFourierTransform<Value, Angle, 2 * N>>(
      f_cos_N⁻¹π, N⁻¹π);
  auto const& a = *fft;

  // [Gen72b] equation (7), factoring out the division by N.
  Value Σʺ{};
  for (std::int64_t n = 0; n <= N; n += 2) {
    // The notation g is from [OLBC10], 3.5.17.
    int const gₙ = n == 0 || n == N ? 1 : 2;
    Σʺ += a[n].real_part() * gₙ / (1 - n * n);
  }
  Σʺ /= N;

  return Σʺ * half_width;
}

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument> GaussLegendre(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound) {
  static_assert(points < LegendreRoots.size,
                "No table for Gauss-Legendre with the chosen number of points");
  return Gauss<points>(f,
                       lower_bound,
                       upper_bound,
                       LegendreRoots[points],
                       GaussLegendreWeights[points]);
}

template<int initial_points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument>
AutomaticClenshawCurtis(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    std::optional<double> const max_relative_error,
    std::optional<int> const max_points) {
  using Result = Primitive<std::invoke_result_t<Function, Argument>, Argument>;
  using Value = std::invoke_result_t<Function, Argument>;
  std::vector<Value> f_cos_N⁻¹π_bit_reversed;
  f_cos_N⁻¹π_bit_reversed.reserve(2 * initial_points - 1);
  Result const estimate = ClenshawCurtisImplementation<initial_points>(
      f, lower_bound, upper_bound, f_cos_N⁻¹π_bit_reversed);
  return AutomaticClenshawCurtisImplementation<2 * initial_points - 1>(
      f,
      lower_bound, upper_bound,
      max_relative_error, max_points,
      estimate,
      f_cos_N⁻¹π_bit_reversed);
}

template<int points, typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument> ClenshawCurtis(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound) {
  using Value = std::invoke_result_t<Function, Argument>;
  std::vector<Value> f_cos_N⁻¹π_bit_reversed;
  f_cos_N⁻¹π_bit_reversed.reserve(points);
  return ClenshawCurtisImplementation<points>(
      f, lower_bound, upper_bound, f_cos_N⁻¹π_bit_reversed);
}

template<typename Argument, typename Function>
Primitive<std::invoke_result_t<Function, Argument>, Argument> Midpoint(
    Function const& f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    int const intervals) {
  Difference<Argument> const h = (upper_bound - lower_bound) / intervals;
  Primitive<std::invoke_result_t<Function, Argument>, Argument> result{};
  for (int i = 0; i < intervals; ++i) {
    result += f(lower_bound + (i + 0.5) * h) * h;
  }
  return result;
}

}  // namespace internal_quadrature
}  // namespace quadrature
}  // namespace numerics
}  // namespace principia
<|endoftext|>


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

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <sstream>
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/Directory.h>

#include "Magnum/ColorFormat.h"
#include "Magnum/Trade/ImageData.h"
#include "MagnumPlugins/TgaImporter/TgaImporter.h"

#include "configure.h"

namespace Magnum { namespace Trade { namespace Test {

class TgaImporterTest: public TestSuite::Tester {
    public:
        TgaImporterTest();

        void openNonexistent();
        void openShort();
        void paletted();
        void compressed();

        void colorBits16();
        void colorBits24();
        void colorBits32();

        void grayscaleBits8();
        void grayscaleBits16();

        void file();
};

TgaImporterTest::TgaImporterTest() {
    addTests({&TgaImporterTest::openNonexistent,
              &TgaImporterTest::openShort,
              &TgaImporterTest::paletted,
              &TgaImporterTest::compressed,

              &TgaImporterTest::colorBits16,
              &TgaImporterTest::colorBits24,
              &TgaImporterTest::colorBits32,

              &TgaImporterTest::grayscaleBits8,
              &TgaImporterTest::grayscaleBits16,

              &TgaImporterTest::file});
}

void TgaImporterTest::openNonexistent() {
    std::ostringstream debug;
    Error::setOutput(&debug);

    TgaImporter importer;
    CORRADE_VERIFY(!importer.openFile("nonexistent.file"));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::openFile(): cannot open file nonexistent.file\n");
}

void TgaImporterTest::openShort() {
    TgaImporter importer;
    const char data[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): the file is too short: 17 bytes\n");
}

void TgaImporterTest::paletted() {
    TgaImporter importer;
    const char data[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): paletted files are not supported\n");
}

void TgaImporterTest::compressed() {
    TgaImporter importer;
    const char data[] = { 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported (compressed?) image type: 9\n");
}

void TgaImporterTest::colorBits16() {
    TgaImporter importer;
    const char data[] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported color bits-per-pixel: 16\n");
}

void TgaImporterTest::colorBits24() {
    TgaImporter importer;
    const char data[] = {
        0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 24, 0,
        1, 2, 3, 2, 3, 4,
        3, 4, 5, 4, 5, 6,
        5, 6, 7, 6, 7, 8
    };
    const char pixels[] = {
        3, 2, 1, 4, 3, 2,
        5, 4, 3, 6, 5, 4,
        7, 6, 5, 8, 7, 6
    };
    CORRADE_VERIFY(importer.openData(data));

    std::optional<Trade::ImageData2D> image = importer.image2D(0);
    CORRADE_VERIFY(image);
    CORRADE_COMPARE(image->format(), ColorFormat::RGB);
    CORRADE_COMPARE(image->size(), Vector2i(2, 3));
    CORRADE_COMPARE(image->type(), ColorType::UnsignedByte);
    CORRADE_COMPARE((std::string{image->data(), 2*3*3}),
                    (std::string{pixels, 2*3*3}));
}

void TgaImporterTest::colorBits32() {
    TgaImporter importer;
    const char data[] = {
        0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 32, 0,
        1, 2, 3, 1, 2, 3, 4, 1,
        3, 4, 5, 1, 4, 5, 6, 1,
        5, 6, 7, 1, 6, 7, 8, 1
    };
    const char pixels[] = {
        3, 2, 1, 1, 4, 3, 2, 1,
        5, 4, 3, 1, 6, 5, 4, 1,
        7, 6, 5, 1, 8, 7, 6, 1
    };
    CORRADE_VERIFY(importer.openData(data));

    std::optional<Trade::ImageData2D> image = importer.image2D(0);
    CORRADE_VERIFY(image);
    CORRADE_COMPARE(image->format(), ColorFormat::RGBA);
    CORRADE_COMPARE(image->size(), Vector2i(2, 3));
    CORRADE_COMPARE(image->type(), ColorType::UnsignedByte);
    CORRADE_COMPARE((std::string{image->data(), 2*3*3}),
                    (std::string{pixels, 2*3*3}));
}

void TgaImporterTest::grayscaleBits8() {
    TgaImporter importer;
    const char data[] = {
        0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0,
        1, 2,
        3, 4,
        5, 6
    };
    CORRADE_VERIFY(importer.openData(data));

    std::optional<Trade::ImageData2D> image = importer.image2D(0);
    CORRADE_VERIFY(image);
    #ifndef MAGNUM_TARGET_GLES2
    CORRADE_COMPARE(image->format(), ColorFormat::Red);
    #else
    CORRADE_COMPARE(image->format(), ColorFormat::Luminance);
    #endif
    CORRADE_COMPARE(image->size(), Vector2i(2, 3));
    CORRADE_COMPARE(image->type(), ColorType::UnsignedByte);
    CORRADE_COMPARE((std::string{image->data(), 2*3}),
                    (std::string{data + 18, 2*3}));
}

void TgaImporterTest::grayscaleBits16() {
    TgaImporter importer;
    const char data[] = { 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported grayscale bits-per-pixel: 16\n");
}

void TgaImporterTest::file() {
    TgaImporter importer;
    const char data[] = {
        0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0,
        1, 2,
        3, 4,
        5, 6
    };
    CORRADE_VERIFY(importer.openFile(Utility::Directory::join(TGAIMPORTER_TEST_DIR, "file.tga")));

    std::optional<Trade::ImageData2D> image = importer.image2D(0);
    CORRADE_VERIFY(image);
    #ifndef MAGNUM_TARGET_GLES2
    CORRADE_COMPARE(image->format(), ColorFormat::Red);
    #else
    CORRADE_COMPARE(image->format(), ColorFormat::Luminance);
    #endif
    CORRADE_COMPARE(image->size(), Vector2i(2, 3));
    CORRADE_COMPARE(image->type(), ColorType::UnsignedByte);
    CORRADE_COMPARE((std::string{image->data(), 2*3}),
                    (std::string{data + 18, 2*3}));
}

}}}

CORRADE_TEST_MAIN(Magnum::Trade::Test::TgaImporterTest)
<commit_msg>TgaImporter: simplified data comparison in test.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <sstream>
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/Directory.h>

#include "Magnum/ColorFormat.h"
#include "Magnum/Trade/ImageData.h"
#include "MagnumPlugins/TgaImporter/TgaImporter.h"

#include "configure.h"

namespace Magnum { namespace Trade { namespace Test {

class TgaImporterTest: public TestSuite::Tester {
    public:
        TgaImporterTest();

        void openNonexistent();
        void openShort();
        void paletted();
        void compressed();

        void colorBits16();
        void colorBits24();
        void colorBits32();

        void grayscaleBits8();
        void grayscaleBits16();

        void file();
};

TgaImporterTest::TgaImporterTest() {
    addTests({&TgaImporterTest::openNonexistent,
              &TgaImporterTest::openShort,
              &TgaImporterTest::paletted,
              &TgaImporterTest::compressed,

              &TgaImporterTest::colorBits16,
              &TgaImporterTest::colorBits24,
              &TgaImporterTest::colorBits32,

              &TgaImporterTest::grayscaleBits8,
              &TgaImporterTest::grayscaleBits16,

              &TgaImporterTest::file});
}

void TgaImporterTest::openNonexistent() {
    std::ostringstream debug;
    Error::setOutput(&debug);

    TgaImporter importer;
    CORRADE_VERIFY(!importer.openFile("nonexistent.file"));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::openFile(): cannot open file nonexistent.file\n");
}

void TgaImporterTest::openShort() {
    TgaImporter importer;
    const char data[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): the file is too short: 17 bytes\n");
}

void TgaImporterTest::paletted() {
    TgaImporter importer;
    const char data[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): paletted files are not supported\n");
}

void TgaImporterTest::compressed() {
    TgaImporter importer;
    const char data[] = { 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported (compressed?) image type: 9\n");
}

void TgaImporterTest::colorBits16() {
    TgaImporter importer;
    const char data[] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported color bits-per-pixel: 16\n");
}

void TgaImporterTest::colorBits24() {
    TgaImporter importer;
    const char data[] = {
        0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 24, 0,
        1, 2, 3, 2, 3, 4,
        3, 4, 5, 4, 5, 6,
        5, 6, 7, 6, 7, 8
    };
    const char pixels[] = {
        3, 2, 1, 4, 3, 2,
        5, 4, 3, 6, 5, 4,
        7, 6, 5, 8, 7, 6
    };
    CORRADE_VERIFY(importer.openData(data));

    std::optional<Trade::ImageData2D> image = importer.image2D(0);
    CORRADE_VERIFY(image);
    CORRADE_COMPARE(image->format(), ColorFormat::RGB);
    CORRADE_COMPARE(image->size(), Vector2i(2, 3));
    CORRADE_COMPARE(image->type(), ColorType::UnsignedByte);
    CORRADE_COMPARE_AS(image->data(), Containers::ArrayView<const char>{pixels},
        TestSuite::Compare::Container);
}

void TgaImporterTest::colorBits32() {
    TgaImporter importer;
    const char data[] = {
        0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 32, 0,
        1, 2, 3, 1, 2, 3, 4, 1,
        3, 4, 5, 1, 4, 5, 6, 1,
        5, 6, 7, 1, 6, 7, 8, 1
    };
    const char pixels[] = {
        3, 2, 1, 1, 4, 3, 2, 1,
        5, 4, 3, 1, 6, 5, 4, 1,
        7, 6, 5, 1, 8, 7, 6, 1
    };
    CORRADE_VERIFY(importer.openData(data));

    std::optional<Trade::ImageData2D> image = importer.image2D(0);
    CORRADE_VERIFY(image);
    CORRADE_COMPARE(image->format(), ColorFormat::RGBA);
    CORRADE_COMPARE(image->size(), Vector2i(2, 3));
    CORRADE_COMPARE(image->type(), ColorType::UnsignedByte);
    CORRADE_COMPARE_AS(image->data(), Containers::ArrayView<const char>{pixels},
        TestSuite::Compare::Container);
}

void TgaImporterTest::grayscaleBits8() {
    TgaImporter importer;
    const char data[] = {
        0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0,
        1, 2,
        3, 4,
        5, 6
    };
    CORRADE_VERIFY(importer.openData(data));

    std::optional<Trade::ImageData2D> image = importer.image2D(0);
    CORRADE_VERIFY(image);
    #ifndef MAGNUM_TARGET_GLES2
    CORRADE_COMPARE(image->format(), ColorFormat::Red);
    #else
    CORRADE_COMPARE(image->format(), ColorFormat::Luminance);
    #endif
    CORRADE_COMPARE(image->size(), Vector2i(2, 3));
    CORRADE_COMPARE(image->type(), ColorType::UnsignedByte);
    CORRADE_COMPARE_AS(image->data(), Containers::ArrayView<const char>{data}.suffix(18),
        TestSuite::Compare::Container);
}

void TgaImporterTest::grayscaleBits16() {
    TgaImporter importer;
    const char data[] = { 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0 };
    CORRADE_VERIFY(importer.openData(data));

    std::ostringstream debug;
    Error::setOutput(&debug);
    CORRADE_VERIFY(!importer.image2D(0));
    CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported grayscale bits-per-pixel: 16\n");
}

void TgaImporterTest::file() {
    TgaImporter importer;
    const char data[] = {
        0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0,
        1, 2,
        3, 4,
        5, 6
    };
    CORRADE_VERIFY(importer.openFile(Utility::Directory::join(TGAIMPORTER_TEST_DIR, "file.tga")));

    std::optional<Trade::ImageData2D> image = importer.image2D(0);
    CORRADE_VERIFY(image);
    #ifndef MAGNUM_TARGET_GLES2
    CORRADE_COMPARE(image->format(), ColorFormat::Red);
    #else
    CORRADE_COMPARE(image->format(), ColorFormat::Luminance);
    #endif
    CORRADE_COMPARE(image->size(), Vector2i(2, 3));
    CORRADE_COMPARE(image->type(), ColorType::UnsignedByte);
    CORRADE_COMPARE_AS(image->data(), Containers::ArrayView<const char>{data}.suffix(18),
        TestSuite::Compare::Container);
}

}}}

CORRADE_TEST_MAIN(Magnum::Trade::Test::TgaImporterTest)
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: gtkobject.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 12:52:22 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _VCL_GTKOBJECT_HXX
#define _VCL_GTKOBJECT_HXX

#ifndef _SV_SV_H
#include <sv.h>
#endif
#ifndef _SV_SYSDATA_HXX
#include <sysdata.hxx>
#endif
#ifndef _SV_SALOBJ_HXX
#include <salobj.hxx>
#endif
#ifndef _VCL_GTKFRAME_HXX
#include <plugins/gtk/gtkframe.hxx>
#endif

class GtkSalObject : public SalObject
{
    SystemChildData     m_aSystemData;
    GtkWidget*          m_pSocket;
    GdkRegion*          m_pRegion;

    // signals
    static gboolean     signalButton( GtkWidget*, GdkEventButton*, gpointer );
    static gboolean     signalFocus( GtkWidget*, GdkEventFocus*, gpointer );
    static void         signalDestroy( GtkObject*, gpointer );
public:
    GtkSalObject( GtkSalFrame* pParent );
    virtual ~GtkSalObject();

    // overload all pure virtual methods
     virtual void                   ResetClipRegion();
    virtual USHORT                  GetClipRegionType();
    virtual void                    BeginSetClipRegion( ULONG nRects );
    virtual void                    UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
    virtual void                    EndSetClipRegion();

    virtual void                    SetPosSize( long nX, long nY, long nWidth, long nHeight );
    virtual void                    Show( BOOL bVisible );
    virtual void                    Enable( BOOL nEnable );
    virtual void                    GrabFocus();

    virtual void                    SetBackground();
    virtual void                    SetBackground( SalColor nSalColor );

    virtual const SystemEnvData*    GetSystemData() const;

};

#endif // _SV_SALOBJ_H
<commit_msg>INTEGRATION: CWS vgbugs07 (1.4.606); FILE MERGED 2007/06/04 13:29:58 vg 1.4.606.1: #i76605# Remove -I .../inc/module hack introduced by hedaburemove01<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: gtkobject.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 20:45:02 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _VCL_GTKOBJECT_HXX
#define _VCL_GTKOBJECT_HXX

#ifndef _SV_SV_H
#include <vcl/sv.h>
#endif
#ifndef _SV_SYSDATA_HXX
#include <sysdata.hxx>
#endif
#ifndef _SV_SALOBJ_HXX
#include <vcl/salobj.hxx>
#endif
#ifndef _VCL_GTKFRAME_HXX
#include <plugins/gtk/gtkframe.hxx>
#endif

class GtkSalObject : public SalObject
{
    SystemChildData     m_aSystemData;
    GtkWidget*          m_pSocket;
    GdkRegion*          m_pRegion;

    // signals
    static gboolean     signalButton( GtkWidget*, GdkEventButton*, gpointer );
    static gboolean     signalFocus( GtkWidget*, GdkEventFocus*, gpointer );
    static void         signalDestroy( GtkObject*, gpointer );
public:
    GtkSalObject( GtkSalFrame* pParent );
    virtual ~GtkSalObject();

    // overload all pure virtual methods
     virtual void                   ResetClipRegion();
    virtual USHORT                  GetClipRegionType();
    virtual void                    BeginSetClipRegion( ULONG nRects );
    virtual void                    UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
    virtual void                    EndSetClipRegion();

    virtual void                    SetPosSize( long nX, long nY, long nWidth, long nHeight );
    virtual void                    Show( BOOL bVisible );
    virtual void                    Enable( BOOL nEnable );
    virtual void                    GrabFocus();

    virtual void                    SetBackground();
    virtual void                    SetBackground( SalColor nSalColor );

    virtual const SystemEnvData*    GetSystemData() const;

};

#endif // _SV_SALOBJ_H
<|endoftext|>