<commit_before>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <set>

#include "webrtc/modules/video_coding/sequence_number_util.h"
#include "webrtc/test/gtest.h"

namespace webrtc {
class TestSeqNumUtil : public ::testing::Test {
 protected:
  // Can't use std::numeric_limits<unsigned long>::max() since
  // MSVC doesn't support constexpr.
  static const unsigned long ulmax = ~0ul;  // NOLINT
};

TEST_F(TestSeqNumUtil, AheadOrAt) {
  uint8_t x = 0;
  uint8_t y = 0;
  ASSERT_TRUE(AheadOrAt(x, y));
  ++x;
  ASSERT_TRUE(AheadOrAt(x, y));
  ASSERT_FALSE(AheadOrAt(y, x));
  for (int i = 0; i < 256; ++i) {
    ASSERT_TRUE(AheadOrAt(x, y));
    ++x;
    ++y;
  }

  x = 128;
  y = 0;
  ASSERT_TRUE(AheadOrAt(x, y));
  ASSERT_FALSE(AheadOrAt(y, x));

  x = 129;
  ASSERT_FALSE(AheadOrAt(x, y));
  ASSERT_TRUE(AheadOrAt(y, x));
  ASSERT_TRUE(AheadOrAt<uint16_t>(x, y));
  ASSERT_FALSE(AheadOrAt<uint16_t>(y, x));
}

TEST_F(TestSeqNumUtil, AheadOrAtWithDivisor) {
  ASSERT_TRUE((AheadOrAt<uint8_t, 11>(5, 0)));
  ASSERT_FALSE((AheadOrAt<uint8_t, 11>(6, 0)));
  ASSERT_FALSE((AheadOrAt<uint8_t, 11>(0, 5)));
  ASSERT_TRUE((AheadOrAt<uint8_t, 11>(0, 6)));

  ASSERT_TRUE((AheadOrAt<uint8_t, 10>(5, 0)));
  ASSERT_FALSE((AheadOrAt<uint8_t, 10>(6, 0)));
  ASSERT_FALSE((AheadOrAt<uint8_t, 10>(0, 5)));
  ASSERT_TRUE((AheadOrAt<uint8_t, 10>(0, 6)));

  const uint8_t D = 211;
  uint8_t x = 0;
  for (int i = 0; i < D; ++i) {
    uint8_t next_x = Add<D>(x, 1);
    ASSERT_TRUE((AheadOrAt<uint8_t, D>(i, i)));
    ASSERT_TRUE((AheadOrAt<uint8_t, D>(next_x, i)));
    ASSERT_FALSE((AheadOrAt<uint8_t, D>(i, next_x)));
    x = next_x;
  }
}

TEST_F(TestSeqNumUtil, AheadOf) {
  uint8_t x = 0;
  uint8_t y = 0;
  ASSERT_FALSE(AheadOf(x, y));
  ++x;
  ASSERT_TRUE(AheadOf(x, y));
  ASSERT_FALSE(AheadOf(y, x));
  for (int i = 0; i < 256; ++i) {
    ASSERT_TRUE(AheadOf(x, y));
    ++x;
    ++y;
  }

  x = 128;
  y = 0;
  for (int i = 0; i < 128; ++i) {
    ASSERT_TRUE(AheadOf(x, y));
    ASSERT_FALSE(AheadOf(y, x));
    x++;
    y++;
  }

  for (int i = 0; i < 128; ++i) {
    ASSERT_FALSE(AheadOf(x, y));
    ASSERT_TRUE(AheadOf(y, x));
    x++;
    y++;
  }

  x = 129;
  y = 0;
  ASSERT_FALSE(AheadOf(x, y));
  ASSERT_TRUE(AheadOf(y, x));
  ASSERT_TRUE(AheadOf<uint16_t>(x, y));
  ASSERT_FALSE(AheadOf<uint16_t>(y, x));
}

TEST_F(TestSeqNumUtil, AheadOfWithDivisor) {
  ASSERT_TRUE((AheadOf<uint8_t, 11>(5, 0)));
  ASSERT_FALSE((AheadOf<uint8_t, 11>(6, 0)));
  ASSERT_FALSE((AheadOf<uint8_t, 11>(0, 5)));
  ASSERT_TRUE((AheadOf<uint8_t, 11>(0, 6)));

  ASSERT_TRUE((AheadOf<uint8_t, 10>(5, 0)));
  ASSERT_FALSE((AheadOf<uint8_t, 10>(6, 0)));
  ASSERT_FALSE((AheadOf<uint8_t, 10>(0, 5)));
  ASSERT_TRUE((AheadOf<uint8_t, 10>(0, 6)));

  const uint8_t D = 211;
  uint8_t x = 0;
  for (int i = 0; i < D; ++i) {
    uint8_t next_x = Add<D>(x, 1);
    ASSERT_FALSE((AheadOf<uint8_t, D>(i, i)));
    ASSERT_TRUE((AheadOf<uint8_t, D>(next_x, i)));
    ASSERT_FALSE((AheadOf<uint8_t, D>(i, next_x)));
    x = next_x;
  }
}

TEST_F(TestSeqNumUtil, ForwardDiffWithDivisor) {
  const uint8_t kDivisor = 211;

  for (uint8_t i = 0; i < kDivisor - 1; ++i) {
    ASSERT_EQ(0, (ForwardDiff<uint8_t, kDivisor>(i, i)));
    ASSERT_EQ(1, (ForwardDiff<uint8_t, kDivisor>(i, i + 1)));
    ASSERT_EQ(kDivisor - 1, (ForwardDiff<uint8_t, kDivisor>(i + 1, i)));
  }

  for (uint8_t i = 1; i < kDivisor; ++i) {
    ASSERT_EQ(i, (ForwardDiff<uint8_t, kDivisor>(0, i)));
    ASSERT_EQ(kDivisor - i, (ForwardDiff<uint8_t, kDivisor>(i, 0)));
  }
}

TEST_F(TestSeqNumUtil, ReverseDiffWithDivisor) {
  const uint8_t kDivisor = 241;

  for (uint8_t i = 0; i < kDivisor - 1; ++i) {
    ASSERT_EQ(0, (ReverseDiff<uint8_t, kDivisor>(i, i)));
    ASSERT_EQ(kDivisor - 1, (ReverseDiff<uint8_t, kDivisor>(i, i + 1)));
    ASSERT_EQ(1, (ReverseDiff<uint8_t, kDivisor>(i + 1, i)));
  }

  for (uint8_t i = 1; i < kDivisor; ++i) {
    ASSERT_EQ(kDivisor - i, (ReverseDiff<uint8_t, kDivisor>(0, i)));
    ASSERT_EQ(i, (ReverseDiff<uint8_t, kDivisor>(i, 0)));
  }
}

TEST_F(TestSeqNumUtil, SeqNumComparator) {
  std::set<uint8_t, AscendingSeqNumComp<uint8_t>> seq_nums_asc;
  std::set<uint8_t, DescendingSeqNumComp<uint8_t>> seq_nums_desc;

  uint8_t x = 0;
  for (int i = 0; i < 128; ++i) {
    seq_nums_asc.insert(x);
    seq_nums_desc.insert(x);
    ASSERT_EQ(x, *seq_nums_asc.begin());
    ASSERT_EQ(x, *seq_nums_desc.rbegin());
    ++x;
  }

  seq_nums_asc.clear();
  seq_nums_desc.clear();
  x = 199;
  for (int i = 0; i < 128; ++i) {
    seq_nums_asc.insert(x);
    seq_nums_desc.insert(x);
    ASSERT_EQ(x, *seq_nums_asc.begin());
    ASSERT_EQ(x, *seq_nums_desc.rbegin());
    ++x;
  }
}

TEST_F(TestSeqNumUtil, SeqNumComparatorWithDivisor) {
  const uint8_t D = 223;

  std::set<uint8_t, AscendingSeqNumComp<uint8_t, D>> seq_nums_asc;
  std::set<uint8_t, DescendingSeqNumComp<uint8_t, D>> seq_nums_desc;

  uint8_t x = 0;
  for (int i = 0; i < D / 2; ++i) {
    seq_nums_asc.insert(x);
    seq_nums_desc.insert(x);
    ASSERT_EQ(x, *seq_nums_asc.begin());
    ASSERT_EQ(x, *seq_nums_desc.rbegin());
    x = Add<D>(x, 1);
  }

  seq_nums_asc.clear();
  seq_nums_desc.clear();
  x = 200;
  for (int i = 0; i < D / 2; ++i) {
    seq_nums_asc.insert(x);
    seq_nums_desc.insert(x);
    ASSERT_EQ(x, *seq_nums_asc.begin());
    ASSERT_EQ(x, *seq_nums_desc.rbegin());
    x = Add<D>(x, 1);
  }
}

TEST(SeqNumUnwrapper, NoBackWardWrap) {
  SeqNumUnwrapper<uint8_t> unwrapper;
  EXPECT_EQ(0U, unwrapper.Unwrap(0));

  // The unwrapped sequence is not allowed to wrap, if that happens the
  // SeqNumUnwrapper should have been constructed with a higher start value.
  ASSERT_DEATH_IF_SUPPORTED(unwrapper.Unwrap(255), "");
}

TEST(SeqNumUnwrapper, NoForwardWrap) {
  SeqNumUnwrapper<uint32_t> unwrapper(std::numeric_limits<uint64_t>::max());
  EXPECT_EQ(std::numeric_limits<uint64_t>::max(), unwrapper.Unwrap(0));

  // The unwrapped sequence is not allowed to wrap, if that happens the
  // SeqNumUnwrapper should have been constructed with a lower start value.
  ASSERT_DEATH_IF_SUPPORTED(unwrapper.Unwrap(1), "");
}

TEST(SeqNumUnwrapper, ForwardWrap) {
  SeqNumUnwrapper<uint8_t> unwrapper;
  EXPECT_EQ(0U, unwrapper.Unwrap(255));
  EXPECT_EQ(1U, unwrapper.Unwrap(0));
}

TEST(SeqNumUnwrapper, ForwardWrapWithDivisor) {
  SeqNumUnwrapper<uint8_t, 33> unwrapper;
  EXPECT_EQ(0U, unwrapper.Unwrap(30));
  EXPECT_EQ(6U, unwrapper.Unwrap(3));
}

TEST(SeqNumUnwrapper, BackWardWrap) {
  SeqNumUnwrapper<uint8_t> unwrapper(10);
  EXPECT_EQ(10U, unwrapper.Unwrap(0));
  EXPECT_EQ(8U, unwrapper.Unwrap(254));
}

TEST(SeqNumUnwrapper, BackWardWrapWithDivisor) {
  SeqNumUnwrapper<uint8_t, 33> unwrapper(10);
  EXPECT_EQ(10U, unwrapper.Unwrap(0));
  EXPECT_EQ(8U, unwrapper.Unwrap(31));
}

TEST(SeqNumUnwrapper, Unwrap) {
  SeqNumUnwrapper<uint16_t> unwrapper;
  const uint16_t kMax = std::numeric_limits<uint16_t>::max();
  const uint16_t kMaxDist = kMax / 2 + 1;

  EXPECT_EQ(0U, unwrapper.Unwrap(0));
  EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist));
  EXPECT_EQ(0U, unwrapper.Unwrap(0));

  EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist));
  EXPECT_EQ(kMax, unwrapper.Unwrap(kMax));
  EXPECT_EQ(kMax + 1U, unwrapper.Unwrap(0));
  EXPECT_EQ(kMax, unwrapper.Unwrap(kMax));
  EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist));
  EXPECT_EQ(0U, unwrapper.Unwrap(0));
}

TEST(SeqNumUnwrapper, UnwrapOddDivisor) {
  SeqNumUnwrapper<uint8_t, 11> unwrapper(10);

  EXPECT_EQ(10U, unwrapper.Unwrap(10));
  EXPECT_EQ(11U, unwrapper.Unwrap(0));
  EXPECT_EQ(16U, unwrapper.Unwrap(5));
  EXPECT_EQ(21U, unwrapper.Unwrap(10));
  EXPECT_EQ(22U, unwrapper.Unwrap(0));
  EXPECT_EQ(17U, unwrapper.Unwrap(6));
  EXPECT_EQ(12U, unwrapper.Unwrap(1));
  EXPECT_EQ(7U, unwrapper.Unwrap(7));
  EXPECT_EQ(2U, unwrapper.Unwrap(2));
  EXPECT_EQ(0U, unwrapper.Unwrap(0));
}

TEST(SeqNumUnwrapper, ManyForwardWraps) {
  const int kLargeNumber = 4711;
  const int kMaxStep = kLargeNumber / 2;
  const int kNumWraps = 100;
  SeqNumUnwrapper<uint16_t, kLargeNumber> unwrapper;

  uint16_t next_unwrap = 0;
  uint64_t expected = 0;
  for (int i = 0; i < kNumWraps * 2 + 1; ++i) {
    EXPECT_EQ(expected, unwrapper.Unwrap(next_unwrap));
    expected += kMaxStep;
    next_unwrap = (next_unwrap + kMaxStep) % kLargeNumber;
  }
}

TEST(SeqNumUnwrapper, ManyBackwardWraps) {
  const int kLargeNumber = 4711;
  const int kMaxStep = kLargeNumber / 2;
  const int kNumWraps = 100;
  SeqNumUnwrapper<uint16_t, kLargeNumber> unwrapper(kLargeNumber * kNumWraps);

  uint16_t next_unwrap = 0;
  uint64_t expected = kLargeNumber * kNumWraps;
  for (uint16_t i = 0; i < kNumWraps * 2 + 1; ++i) {
    EXPECT_EQ(expected, unwrapper.Unwrap(next_unwrap));
    expected -= kMaxStep;
    next_unwrap = (next_unwrap + kMaxStep + 1) % kLargeNumber;
  }
}

}  // namespace webrtc
<commit_msg>Disable SeqNumUnwrapper death tests to avoid breaking downstream builds.<commit_after>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <set>

#include "webrtc/modules/video_coding/sequence_number_util.h"
#include "webrtc/test/gtest.h"

namespace webrtc {
class TestSeqNumUtil : public ::testing::Test {
 protected:
  // Can't use std::numeric_limits<unsigned long>::max() since
  // MSVC doesn't support constexpr.
  static const unsigned long ulmax = ~0ul;  // NOLINT
};

TEST_F(TestSeqNumUtil, AheadOrAt) {
  uint8_t x = 0;
  uint8_t y = 0;
  ASSERT_TRUE(AheadOrAt(x, y));
  ++x;
  ASSERT_TRUE(AheadOrAt(x, y));
  ASSERT_FALSE(AheadOrAt(y, x));
  for (int i = 0; i < 256; ++i) {
    ASSERT_TRUE(AheadOrAt(x, y));
    ++x;
    ++y;
  }

  x = 128;
  y = 0;
  ASSERT_TRUE(AheadOrAt(x, y));
  ASSERT_FALSE(AheadOrAt(y, x));

  x = 129;
  ASSERT_FALSE(AheadOrAt(x, y));
  ASSERT_TRUE(AheadOrAt(y, x));
  ASSERT_TRUE(AheadOrAt<uint16_t>(x, y));
  ASSERT_FALSE(AheadOrAt<uint16_t>(y, x));
}

TEST_F(TestSeqNumUtil, AheadOrAtWithDivisor) {
  ASSERT_TRUE((AheadOrAt<uint8_t, 11>(5, 0)));
  ASSERT_FALSE((AheadOrAt<uint8_t, 11>(6, 0)));
  ASSERT_FALSE((AheadOrAt<uint8_t, 11>(0, 5)));
  ASSERT_TRUE((AheadOrAt<uint8_t, 11>(0, 6)));

  ASSERT_TRUE((AheadOrAt<uint8_t, 10>(5, 0)));
  ASSERT_FALSE((AheadOrAt<uint8_t, 10>(6, 0)));
  ASSERT_FALSE((AheadOrAt<uint8_t, 10>(0, 5)));
  ASSERT_TRUE((AheadOrAt<uint8_t, 10>(0, 6)));

  const uint8_t D = 211;
  uint8_t x = 0;
  for (int i = 0; i < D; ++i) {
    uint8_t next_x = Add<D>(x, 1);
    ASSERT_TRUE((AheadOrAt<uint8_t, D>(i, i)));
    ASSERT_TRUE((AheadOrAt<uint8_t, D>(next_x, i)));
    ASSERT_FALSE((AheadOrAt<uint8_t, D>(i, next_x)));
    x = next_x;
  }
}

TEST_F(TestSeqNumUtil, AheadOf) {
  uint8_t x = 0;
  uint8_t y = 0;
  ASSERT_FALSE(AheadOf(x, y));
  ++x;
  ASSERT_TRUE(AheadOf(x, y));
  ASSERT_FALSE(AheadOf(y, x));
  for (int i = 0; i < 256; ++i) {
    ASSERT_TRUE(AheadOf(x, y));
    ++x;
    ++y;
  }

  x = 128;
  y = 0;
  for (int i = 0; i < 128; ++i) {
    ASSERT_TRUE(AheadOf(x, y));
    ASSERT_FALSE(AheadOf(y, x));
    x++;
    y++;
  }

  for (int i = 0; i < 128; ++i) {
    ASSERT_FALSE(AheadOf(x, y));
    ASSERT_TRUE(AheadOf(y, x));
    x++;
    y++;
  }

  x = 129;
  y = 0;
  ASSERT_FALSE(AheadOf(x, y));
  ASSERT_TRUE(AheadOf(y, x));
  ASSERT_TRUE(AheadOf<uint16_t>(x, y));
  ASSERT_FALSE(AheadOf<uint16_t>(y, x));
}

TEST_F(TestSeqNumUtil, AheadOfWithDivisor) {
  ASSERT_TRUE((AheadOf<uint8_t, 11>(5, 0)));
  ASSERT_FALSE((AheadOf<uint8_t, 11>(6, 0)));
  ASSERT_FALSE((AheadOf<uint8_t, 11>(0, 5)));
  ASSERT_TRUE((AheadOf<uint8_t, 11>(0, 6)));

  ASSERT_TRUE((AheadOf<uint8_t, 10>(5, 0)));
  ASSERT_FALSE((AheadOf<uint8_t, 10>(6, 0)));
  ASSERT_FALSE((AheadOf<uint8_t, 10>(0, 5)));
  ASSERT_TRUE((AheadOf<uint8_t, 10>(0, 6)));

  const uint8_t D = 211;
  uint8_t x = 0;
  for (int i = 0; i < D; ++i) {
    uint8_t next_x = Add<D>(x, 1);
    ASSERT_FALSE((AheadOf<uint8_t, D>(i, i)));
    ASSERT_TRUE((AheadOf<uint8_t, D>(next_x, i)));
    ASSERT_FALSE((AheadOf<uint8_t, D>(i, next_x)));
    x = next_x;
  }
}

TEST_F(TestSeqNumUtil, ForwardDiffWithDivisor) {
  const uint8_t kDivisor = 211;

  for (uint8_t i = 0; i < kDivisor - 1; ++i) {
    ASSERT_EQ(0, (ForwardDiff<uint8_t, kDivisor>(i, i)));
    ASSERT_EQ(1, (ForwardDiff<uint8_t, kDivisor>(i, i + 1)));
    ASSERT_EQ(kDivisor - 1, (ForwardDiff<uint8_t, kDivisor>(i + 1, i)));
  }

  for (uint8_t i = 1; i < kDivisor; ++i) {
    ASSERT_EQ(i, (ForwardDiff<uint8_t, kDivisor>(0, i)));
    ASSERT_EQ(kDivisor - i, (ForwardDiff<uint8_t, kDivisor>(i, 0)));
  }
}

TEST_F(TestSeqNumUtil, ReverseDiffWithDivisor) {
  const uint8_t kDivisor = 241;

  for (uint8_t i = 0; i < kDivisor - 1; ++i) {
    ASSERT_EQ(0, (ReverseDiff<uint8_t, kDivisor>(i, i)));
    ASSERT_EQ(kDivisor - 1, (ReverseDiff<uint8_t, kDivisor>(i, i + 1)));
    ASSERT_EQ(1, (ReverseDiff<uint8_t, kDivisor>(i + 1, i)));
  }

  for (uint8_t i = 1; i < kDivisor; ++i) {
    ASSERT_EQ(kDivisor - i, (ReverseDiff<uint8_t, kDivisor>(0, i)));
    ASSERT_EQ(i, (ReverseDiff<uint8_t, kDivisor>(i, 0)));
  }
}

TEST_F(TestSeqNumUtil, SeqNumComparator) {
  std::set<uint8_t, AscendingSeqNumComp<uint8_t>> seq_nums_asc;
  std::set<uint8_t, DescendingSeqNumComp<uint8_t>> seq_nums_desc;

  uint8_t x = 0;
  for (int i = 0; i < 128; ++i) {
    seq_nums_asc.insert(x);
    seq_nums_desc.insert(x);
    ASSERT_EQ(x, *seq_nums_asc.begin());
    ASSERT_EQ(x, *seq_nums_desc.rbegin());
    ++x;
  }

  seq_nums_asc.clear();
  seq_nums_desc.clear();
  x = 199;
  for (int i = 0; i < 128; ++i) {
    seq_nums_asc.insert(x);
    seq_nums_desc.insert(x);
    ASSERT_EQ(x, *seq_nums_asc.begin());
    ASSERT_EQ(x, *seq_nums_desc.rbegin());
    ++x;
  }
}

TEST_F(TestSeqNumUtil, SeqNumComparatorWithDivisor) {
  const uint8_t D = 223;

  std::set<uint8_t, AscendingSeqNumComp<uint8_t, D>> seq_nums_asc;
  std::set<uint8_t, DescendingSeqNumComp<uint8_t, D>> seq_nums_desc;

  uint8_t x = 0;
  for (int i = 0; i < D / 2; ++i) {
    seq_nums_asc.insert(x);
    seq_nums_desc.insert(x);
    ASSERT_EQ(x, *seq_nums_asc.begin());
    ASSERT_EQ(x, *seq_nums_desc.rbegin());
    x = Add<D>(x, 1);
  }

  seq_nums_asc.clear();
  seq_nums_desc.clear();
  x = 200;
  for (int i = 0; i < D / 2; ++i) {
    seq_nums_asc.insert(x);
    seq_nums_desc.insert(x);
    ASSERT_EQ(x, *seq_nums_asc.begin());
    ASSERT_EQ(x, *seq_nums_desc.rbegin());
    x = Add<D>(x, 1);
  }
}

// TODO(philipel): Enable when downstream project can hande these death tests.

TEST(SeqNumUnwrapper, DISABLED_NoBackWardWrap) {
  SeqNumUnwrapper<uint8_t> unwrapper;
  EXPECT_EQ(0U, unwrapper.Unwrap(0));

  // The unwrapped sequence is not allowed to wrap, if that happens the
  // SeqNumUnwrapper should have been constructed with a higher start value.
  ASSERT_DEATH_IF_SUPPORTED(unwrapper.Unwrap(255), "");
}

TEST(SeqNumUnwrapper, DISABLED_NoForwardWrap) {
  SeqNumUnwrapper<uint32_t> unwrapper(std::numeric_limits<uint64_t>::max());
  EXPECT_EQ(std::numeric_limits<uint64_t>::max(), unwrapper.Unwrap(0));

  // The unwrapped sequence is not allowed to wrap, if that happens the
  // SeqNumUnwrapper should have been constructed with a lower start value.
  ASSERT_DEATH_IF_SUPPORTED(unwrapper.Unwrap(1), "");
}

TEST(SeqNumUnwrapper, ForwardWrap) {
  SeqNumUnwrapper<uint8_t> unwrapper;
  EXPECT_EQ(0U, unwrapper.Unwrap(255));
  EXPECT_EQ(1U, unwrapper.Unwrap(0));
}

TEST(SeqNumUnwrapper, ForwardWrapWithDivisor) {
  SeqNumUnwrapper<uint8_t, 33> unwrapper;
  EXPECT_EQ(0U, unwrapper.Unwrap(30));
  EXPECT_EQ(6U, unwrapper.Unwrap(3));
}

TEST(SeqNumUnwrapper, BackWardWrap) {
  SeqNumUnwrapper<uint8_t> unwrapper(10);
  EXPECT_EQ(10U, unwrapper.Unwrap(0));
  EXPECT_EQ(8U, unwrapper.Unwrap(254));
}

TEST(SeqNumUnwrapper, BackWardWrapWithDivisor) {
  SeqNumUnwrapper<uint8_t, 33> unwrapper(10);
  EXPECT_EQ(10U, unwrapper.Unwrap(0));
  EXPECT_EQ(8U, unwrapper.Unwrap(31));
}

TEST(SeqNumUnwrapper, Unwrap) {
  SeqNumUnwrapper<uint16_t> unwrapper;
  const uint16_t kMax = std::numeric_limits<uint16_t>::max();
  const uint16_t kMaxDist = kMax / 2 + 1;

  EXPECT_EQ(0U, unwrapper.Unwrap(0));
  EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist));
  EXPECT_EQ(0U, unwrapper.Unwrap(0));

  EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist));
  EXPECT_EQ(kMax, unwrapper.Unwrap(kMax));
  EXPECT_EQ(kMax + 1U, unwrapper.Unwrap(0));
  EXPECT_EQ(kMax, unwrapper.Unwrap(kMax));
  EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist));
  EXPECT_EQ(0U, unwrapper.Unwrap(0));
}

TEST(SeqNumUnwrapper, UnwrapOddDivisor) {
  SeqNumUnwrapper<uint8_t, 11> unwrapper(10);

  EXPECT_EQ(10U, unwrapper.Unwrap(10));
  EXPECT_EQ(11U, unwrapper.Unwrap(0));
  EXPECT_EQ(16U, unwrapper.Unwrap(5));
  EXPECT_EQ(21U, unwrapper.Unwrap(10));
  EXPECT_EQ(22U, unwrapper.Unwrap(0));
  EXPECT_EQ(17U, unwrapper.Unwrap(6));
  EXPECT_EQ(12U, unwrapper.Unwrap(1));
  EXPECT_EQ(7U, unwrapper.Unwrap(7));
  EXPECT_EQ(2U, unwrapper.Unwrap(2));
  EXPECT_EQ(0U, unwrapper.Unwrap(0));
}

TEST(SeqNumUnwrapper, ManyForwardWraps) {
  const int kLargeNumber = 4711;
  const int kMaxStep = kLargeNumber / 2;
  const int kNumWraps = 100;
  SeqNumUnwrapper<uint16_t, kLargeNumber> unwrapper;

  uint16_t next_unwrap = 0;
  uint64_t expected = 0;
  for (int i = 0; i < kNumWraps * 2 + 1; ++i) {
    EXPECT_EQ(expected, unwrapper.Unwrap(next_unwrap));
    expected += kMaxStep;
    next_unwrap = (next_unwrap + kMaxStep) % kLargeNumber;
  }
}

TEST(SeqNumUnwrapper, ManyBackwardWraps) {
  const int kLargeNumber = 4711;
  const int kMaxStep = kLargeNumber / 2;
  const int kNumWraps = 100;
  SeqNumUnwrapper<uint16_t, kLargeNumber> unwrapper(kLargeNumber * kNumWraps);

  uint16_t next_unwrap = 0;
  uint64_t expected = kLargeNumber * kNumWraps;
  for (uint16_t i = 0; i < kNumWraps * 2 + 1; ++i) {
    EXPECT_EQ(expected, unwrapper.Unwrap(next_unwrap));
    expected -= kMaxStep;
    next_unwrap = (next_unwrap + kMaxStep + 1) % kLargeNumber;
  }
}

}  // namespace webrtc
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "cefclient/download_handler.h"
#include <stdio.h>
#include <sstream>
#include <vector>
#include "include/cef_download_handler.h"
#include "include/cef_runnable.h"
#include "cefclient/util.h"

#if defined(OS_WIN)
#include <windows.h>  // NOLINT(build/include_order)
#include <shlobj.h>  // NOLINT(build/include_order)
#include <shlwapi.h>  // NOLINT(build/include_order)
#endif  // OS_WIN

// Implementation of the CefDownloadHandler interface.
class ClientDownloadHandler : public CefDownloadHandler {
 public:
  ClientDownloadHandler(CefRefPtr<DownloadListener> listener,
                        const CefString& fileName)
    : listener_(listener), filename_(fileName), file_(NULL) {
  }

  ~ClientDownloadHandler() {
    ASSERT(pending_data_.empty());
    ASSERT(file_ == NULL);

    if (!pending_data_.empty()) {
      // Delete remaining pending data.
      std::vector<std::vector<char>*>::iterator it = pending_data_.begin();
      for (; it != pending_data_.end(); ++it)
        delete (*it);
    }

    if (file_) {
      // Close the dangling file pointer on the FILE thread.
      CefPostTask(TID_FILE,
          NewCefRunnableFunction(&ClientDownloadHandler::CloseDanglingFile,
                                 file_));

      // Notify the listener that the download failed.
      listener_->NotifyDownloadError(filename_);
    }
  }

  // --------------------------------------------------
  // The following methods are called on the UI thread.
  // --------------------------------------------------

  void Initialize() {
    // Open the file on the FILE thread.
    CefPostTask(TID_FILE,
        NewCefRunnableMethod(this, &ClientDownloadHandler::OnOpen));
  }

  // A portion of the file contents have been received. This method will be
  // called multiple times until the download is complete. Return |true| to
  // continue receiving data and |false| to cancel.
  virtual bool ReceivedData(void* data, int data_size) {
    REQUIRE_UI_THREAD();

    if (data_size == 0)
      return true;

    // Create a new vector for the data.
    std::vector<char>* buffer = new std::vector<char>(data_size);
    memcpy(&(*buffer)[0], data, data_size);

    // Add the new data vector to the pending data queue.
    {
      AutoLock lock_scope(this);
      pending_data_.push_back(buffer);
    }

    // Write data to file on the FILE thread.
    CefPostTask(TID_FILE,
        NewCefRunnableMethod(this, &ClientDownloadHandler::OnReceivedData));
    return true;
  }

  // The download is complete.
  virtual void Complete() {
    REQUIRE_UI_THREAD();

    // Flush and close the file on the FILE thread.
    CefPostTask(TID_FILE,
        NewCefRunnableMethod(this, &ClientDownloadHandler::OnComplete));
  }

  // ----------------------------------------------------
  // The following methods are called on the FILE thread.
  // ----------------------------------------------------

  void OnOpen() {
    REQUIRE_FILE_THREAD();

    if (file_)
      return;

#if defined(OS_WIN)
    TCHAR szFolderPath[MAX_PATH];

    // Save the file in the user's "My Documents" folder.
    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE,
                                  NULL, 0, szFolderPath))) {
      std::wstring fileNameStr = filename_;
      LPWSTR name = PathFindFileName(fileNameStr.c_str());
      LPWSTR ext = PathFindExtension(fileNameStr.c_str());
      int ct = 0;
      std::wstringstream ss;

      if (ext) {
        name[ext-name] = 0;
        ext++;
      }

      // Make sure the file name is unique.
      do {
        if (ct > 0)
          ss.str(L"");
        ss << szFolderPath << L"\\" << name;
        if (ct > 0)
          ss << L" (" << ct << L")";
        if (ext)
          ss << L"." << ext;
        ct++;
      } while (PathFileExists(ss.str().c_str()));

      {
        AutoLock lock_scope(this);
        filename_ = ss.str();
      }

      file_ = _wfopen(ss.str().c_str(), L"wb");
      ASSERT(file_ != NULL);
    }
#else
    // TODO(port): Implement this.
    ASSERT(false);  // Not implemented
#endif
  }

  void OnComplete() {
    REQUIRE_FILE_THREAD();

    if (!file_)
      return;

    // Make sure any pending data is written.
    OnReceivedData();

    fclose(file_);
    file_ = NULL;

    // Notify the listener that the download completed.
    listener_->NotifyDownloadComplete(filename_);
  }

  void OnReceivedData() {
    REQUIRE_FILE_THREAD();

    std::vector<std::vector<char>*> data;

    // Remove all data from the pending data queue.
    {
      AutoLock lock_scope(this);
      if (!pending_data_.empty()) {
        data = pending_data_;
        pending_data_.clear();
      }
    }

    if (data.empty())
      return;

    // Write all pending data to file.
    std::vector<std::vector<char>*>::iterator it = data.begin();
    for (; it != data.end(); ++it) {
      std::vector<char>* buffer = *it;
      if (file_)
        fwrite(&(*buffer)[0], buffer->size(), 1, file_);
      delete buffer;
    }
    data.clear();
  }

  static void CloseDanglingFile(FILE *file) {
    fclose(file);
  }

 private:
  CefRefPtr<DownloadListener> listener_;
  CefString filename_;
  FILE* file_;
  std::vector<std::vector<char>*> pending_data_;

  IMPLEMENT_REFCOUNTING(ClientDownloadHandler);
  IMPLEMENT_LOCKING(ClientDownloadHandler);
};

CefRefPtr<CefDownloadHandler> CreateDownloadHandler(
    CefRefPtr<DownloadListener> listener, const CefString& fileName) {
  CefRefPtr<ClientDownloadHandler> handler =
      new ClientDownloadHandler(listener, fileName);
  handler->Initialize();
  return handler.get();
}
<commit_msg>Linux: Fix compiler warning about fwrite() return value being ignored.<commit_after>// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "cefclient/download_handler.h"
#include <stdio.h>
#include <sstream>
#include <vector>
#include "include/cef_download_handler.h"
#include "include/cef_runnable.h"
#include "cefclient/util.h"

#if defined(OS_WIN)
#include <windows.h>  // NOLINT(build/include_order)
#include <shlobj.h>  // NOLINT(build/include_order)
#include <shlwapi.h>  // NOLINT(build/include_order)
#endif  // OS_WIN

// Implementation of the CefDownloadHandler interface.
class ClientDownloadHandler : public CefDownloadHandler {
 public:
  ClientDownloadHandler(CefRefPtr<DownloadListener> listener,
                        const CefString& fileName)
    : listener_(listener), filename_(fileName), file_(NULL) {
  }

  ~ClientDownloadHandler() {
    ASSERT(pending_data_.empty());
    ASSERT(file_ == NULL);

    if (!pending_data_.empty()) {
      // Delete remaining pending data.
      std::vector<std::vector<char>*>::iterator it = pending_data_.begin();
      for (; it != pending_data_.end(); ++it)
        delete (*it);
    }

    if (file_) {
      // Close the dangling file pointer on the FILE thread.
      CefPostTask(TID_FILE,
          NewCefRunnableFunction(&ClientDownloadHandler::CloseDanglingFile,
                                 file_));

      // Notify the listener that the download failed.
      listener_->NotifyDownloadError(filename_);
    }
  }

  // --------------------------------------------------
  // The following methods are called on the UI thread.
  // --------------------------------------------------

  void Initialize() {
    // Open the file on the FILE thread.
    CefPostTask(TID_FILE,
        NewCefRunnableMethod(this, &ClientDownloadHandler::OnOpen));
  }

  // A portion of the file contents have been received. This method will be
  // called multiple times until the download is complete. Return |true| to
  // continue receiving data and |false| to cancel.
  virtual bool ReceivedData(void* data, int data_size) {
    REQUIRE_UI_THREAD();

    if (data_size == 0)
      return true;

    // Create a new vector for the data.
    std::vector<char>* buffer = new std::vector<char>(data_size);
    memcpy(&(*buffer)[0], data, data_size);

    // Add the new data vector to the pending data queue.
    {
      AutoLock lock_scope(this);
      pending_data_.push_back(buffer);
    }

    // Write data to file on the FILE thread.
    CefPostTask(TID_FILE,
        NewCefRunnableMethod(this, &ClientDownloadHandler::OnReceivedData));
    return true;
  }

  // The download is complete.
  virtual void Complete() {
    REQUIRE_UI_THREAD();

    // Flush and close the file on the FILE thread.
    CefPostTask(TID_FILE,
        NewCefRunnableMethod(this, &ClientDownloadHandler::OnComplete));
  }

  // ----------------------------------------------------
  // The following methods are called on the FILE thread.
  // ----------------------------------------------------

  void OnOpen() {
    REQUIRE_FILE_THREAD();

    if (file_)
      return;

#if defined(OS_WIN)
    TCHAR szFolderPath[MAX_PATH];

    // Save the file in the user's "My Documents" folder.
    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE,
                                  NULL, 0, szFolderPath))) {
      std::wstring fileNameStr = filename_;
      LPWSTR name = PathFindFileName(fileNameStr.c_str());
      LPWSTR ext = PathFindExtension(fileNameStr.c_str());
      int ct = 0;
      std::wstringstream ss;

      if (ext) {
        name[ext-name] = 0;
        ext++;
      }

      // Make sure the file name is unique.
      do {
        if (ct > 0)
          ss.str(L"");
        ss << szFolderPath << L"\\" << name;
        if (ct > 0)
          ss << L" (" << ct << L")";
        if (ext)
          ss << L"." << ext;
        ct++;
      } while (PathFileExists(ss.str().c_str()));

      {
        AutoLock lock_scope(this);
        filename_ = ss.str();
      }

      file_ = _wfopen(ss.str().c_str(), L"wb");
      ASSERT(file_ != NULL);
    }
#else
    // TODO(port): Implement this.
    ASSERT(false);  // Not implemented
#endif
  }

  void OnComplete() {
    REQUIRE_FILE_THREAD();

    if (!file_)
      return;

    // Make sure any pending data is written.
    OnReceivedData();

    fclose(file_);
    file_ = NULL;

    // Notify the listener that the download completed.
    listener_->NotifyDownloadComplete(filename_);
  }

  void OnReceivedData() {
    REQUIRE_FILE_THREAD();

    std::vector<std::vector<char>*> data;

    // Remove all data from the pending data queue.
    {
      AutoLock lock_scope(this);
      if (!pending_data_.empty()) {
        data = pending_data_;
        pending_data_.clear();
      }
    }

    if (data.empty())
      return;

    // Write all pending data to file.
    std::vector<std::vector<char>*>::iterator it = data.begin();
    for (; it != data.end(); ++it) {
      std::vector<char>* buffer = *it;
      if (file_) {
        size_t total = 0;
        do {
          size_t write =
              fwrite(&(*buffer)[total], 1, buffer->size() - total, file_);
          if (write == 0)
            break;
          total += write;
        } while (total < buffer->size());
      }
      delete buffer;
    }
    data.clear();
  }

  static void CloseDanglingFile(FILE *file) {
    fclose(file);
  }

 private:
  CefRefPtr<DownloadListener> listener_;
  CefString filename_;
  FILE* file_;
  std::vector<std::vector<char>*> pending_data_;

  IMPLEMENT_REFCOUNTING(ClientDownloadHandler);
  IMPLEMENT_LOCKING(ClientDownloadHandler);
};

CefRefPtr<CefDownloadHandler> CreateDownloadHandler(
    CefRefPtr<DownloadListener> listener, const CefString& fileName) {
  CefRefPtr<ClientDownloadHandler> handler =
      new ClientDownloadHandler(listener, fileName);
  handler->Initialize();
  return handler.get();
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "application.h"
#include "log.h"
#include "perfcounter.h"
#include "sysutil.h"
#include "window.h"
#include "devicemanager.h"
#include "keyboarddevice.h"
#include "settings.h"

namespace dukat
{
	Application::Application(Settings& settings)
		: settings(settings), title(settings.get_string("window.title")), paused(false), done(false)
	{
		sdl_check_result(SDL_Init(SDL_INIT_EVERYTHING), "Initialize SDL");
		window = std::make_unique<Window>(settings.get_int("window.width", 640), settings.get_int("window.height", 480),
			settings.get_bool("window.fullscreen"), settings.get_bool("window.msaa"));
		window->set_title(title);
		device_manager = std::make_unique<DeviceManager>();
		device_manager->add_keyboard(window.get());
		device_manager->joystick_support = settings.get_bool("input.joystick.support", true);
		gl_check_error();
	}

	Application::~Application(void)
	{
		SDL_Quit();
	}

	int Application::run(void)
	{
		logger << "Initializing application." << std::endl;
		init();

		logger << "Entering application loop." << std::endl;
		Uint32 ticks, last_update = 0, last_frame = 0;
		SDL_Event e;
		while (!done)
		{
			ticks = SDL_GetTicks();

			device_manager->update();
			if (!paused)
			{
				update(((float)(ticks - last_update)) / 1000.0f);
			}
			last_update = SDL_GetTicks();

			// update FPS counter
			if (ticks - last_frame >= 1000)
			{
				last_fps = perfc.sum(PerformanceCounter::FRAMES);
				last_frame = ticks;
				perfc.collect_stats();
			}

			// process events
			while (SDL_PollEvent(&e))
			{
				handle_event(e);
			}

			// render to screen
			render();
			perfc.inc(PerformanceCounter::FRAMES);
			perfc.reset();
		}

		release();

		return 0;
	}

	void Application::handle_event(const SDL_Event& e)
	{
		switch (e.type)
		{
		case SDL_QUIT:
			done = true;
			break;
		case SDL_KEYDOWN:
			handle_keyboard(e);
			break;
		case SDL_WINDOWEVENT:
			handle_window_event(e);
			break;
		case SDL_JOYDEVICEADDED:
			device_manager->add_joystick(window.get(), e.jdevice.which);
			break;
		case SDL_JOYDEVICEREMOVED:
			device_manager->remove_joystick(e.jdevice.which);
			break;
		}
	}

	void Application::handle_keyboard(const SDL_Event& e)
	{
		switch (e.key.keysym.sym)
		{
		case SDLK_ESCAPE:
			done = true;
			break;
		case SDLK_RETURN:
			if (e.key.keysym.mod & KMOD_ALT)
			{
				window->toggle_fullscreen();
			}
			break;
		case SDLK_F12:
			save_screenshot("screenshot.png");
			break;
		}
	}

	void Application::handle_window_event(const SDL_Event& e)
	{
		switch (e.window.event)
		{
		case SDL_WINDOWEVENT_FOCUS_GAINED:
			if (settings.get_bool("input.mouse.lock", true))
			{
				sdl_check_result(SDL_SetRelativeMouseMode(SDL_TRUE), "Set mouse mode");
			}
	        break;
        case SDL_WINDOWEVENT_FOCUS_LOST:
    		if (settings.get_bool("input.mouse.lock", true))
			{
				sdl_check_result(SDL_SetRelativeMouseMode(SDL_FALSE), "Set mouse mode");
			}
	        break;
		}
	}
}<commit_msg>Fixed application timer<commit_after>#include "stdafx.h"
#include "application.h"
#include "log.h"
#include "perfcounter.h"
#include "sysutil.h"
#include "window.h"
#include "devicemanager.h"
#include "keyboarddevice.h"
#include "settings.h"

namespace dukat
{
	Application::Application(Settings& settings)
		: settings(settings), title(settings.get_string("window.title")), paused(false), done(false)
	{
		sdl_check_result(SDL_Init(SDL_INIT_EVERYTHING), "Initialize SDL");
		window = std::make_unique<Window>(settings.get_int("window.width", 640), settings.get_int("window.height", 480),
			settings.get_bool("window.fullscreen"), settings.get_bool("window.msaa"));
		window->set_title(title);
		device_manager = std::make_unique<DeviceManager>();
		device_manager->add_keyboard(window.get());
		device_manager->joystick_support = settings.get_bool("input.joystick.support", true);
		gl_check_error();
	}

	Application::~Application(void)
	{
		SDL_Quit();
	}

	int Application::run(void)
	{
		logger << "Initializing application." << std::endl;
		init();

		logger << "Entering application loop." << std::endl;
		Uint32 ticks, last_update = 0, last_frame = 0;
		SDL_Event e;
		while (!done)
		{
			ticks = SDL_GetTicks();

			device_manager->update();
			if (!paused)
			{
				update(((float)(ticks - last_update)) / 1000.0f);
			}
			last_update = ticks;

			// update FPS counter
			if (ticks - last_frame >= 1000)
			{
				last_fps = perfc.sum(PerformanceCounter::FRAMES);
				last_frame = ticks;
				perfc.collect_stats();
			}

			// process events
			while (SDL_PollEvent(&e))
			{
				handle_event(e);
			}

			// render to screen
			render();
			perfc.inc(PerformanceCounter::FRAMES);
			perfc.reset();
		}

		release();

		return 0;
	}

	void Application::handle_event(const SDL_Event& e)
	{
		switch (e.type)
		{
		case SDL_QUIT:
			done = true;
			break;
		case SDL_KEYDOWN:
			handle_keyboard(e);
			break;
		case SDL_WINDOWEVENT:
			handle_window_event(e);
			break;
		case SDL_JOYDEVICEADDED:
			device_manager->add_joystick(window.get(), e.jdevice.which);
			break;
		case SDL_JOYDEVICEREMOVED:
			device_manager->remove_joystick(e.jdevice.which);
			break;
		}
	}

	void Application::handle_keyboard(const SDL_Event& e)
	{
		switch (e.key.keysym.sym)
		{
		case SDLK_ESCAPE:
			done = true;
			break;
		case SDLK_RETURN:
			if (e.key.keysym.mod & KMOD_ALT)
			{
				window->toggle_fullscreen();
			}
			break;
		case SDLK_PAUSE:
			toggle_pause();
			break;
		case SDLK_F12:
			save_screenshot("screenshot.png");
			break;
		}
	}

	void Application::handle_window_event(const SDL_Event& e)
	{
		switch (e.window.event)
		{
		case SDL_WINDOWEVENT_FOCUS_GAINED:
			if (settings.get_bool("input.mouse.lock", true))
			{
				sdl_check_result(SDL_SetRelativeMouseMode(SDL_TRUE), "Set mouse mode");
			}
	        break;
        case SDL_WINDOWEVENT_FOCUS_LOST:
    		if (settings.get_bool("input.mouse.lock", true))
			{
				sdl_check_result(SDL_SetRelativeMouseMode(SDL_FALSE), "Set mouse mode");
			}
	        break;
		}
	}
}<|endoftext|>


<commit_before>/************************************
 * file enc : ASCII
 * author   : wuyanyi09@gmail.com
 ************************************/
#ifndef CPPJIEBA_TRIE_H
#define CPPJIEBA_TRIE_H

#include <iostream>
#include <fstream>
#include <map>
#include <cstring>
#include <stdint.h>
#include <cmath>
#include <limits>
#include "Limonp/str_functs.hpp"
#include "Limonp/logger.hpp"
#include "TransCode.hpp"

namespace CppJieba
{
    using namespace Limonp;
    const double MIN_DOUBLE = -3.14e+100;
    const double MAX_DOUBLE = 3.14e+100;
    typedef unordered_map<uint16_t, struct TrieNode*> TrieNodeMap;
    struct TrieNode
    {
        TrieNodeMap hmap;
        bool isLeaf;
        uint nodeInfoVecPos;
        TrieNode()
        {
            isLeaf = false;
            nodeInfoVecPos = 0;
        }
    };

    struct TrieNodeInfo
    {
        Unicode word;
        size_t freq;
        string tag;
        double logFreq; //logFreq = log(freq/sum(freq));
        TrieNodeInfo():freq(0),logFreq(0.0)
        {
        }
        TrieNodeInfo(const TrieNodeInfo& nodeInfo):word(nodeInfo.word), freq(nodeInfo.freq), tag(nodeInfo.tag), logFreq(nodeInfo.logFreq)
        {
        }
        TrieNodeInfo(const Unicode& _word):word(_word),freq(0),logFreq(MIN_DOUBLE)
        {
        }
        bool operator == (const TrieNodeInfo & rhs) const
        {
            return word == rhs.word && freq == rhs.freq && tag == rhs.tag && abs(logFreq - rhs.logFreq) < 0.001;
        }
    };

    inline ostream& operator << (ostream& os, const TrieNodeInfo & nodeInfo)
    {
        return os << nodeInfo.word << ":" << nodeInfo.freq << ":" << nodeInfo.tag << ":" << nodeInfo.logFreq ;
    }

    typedef unordered_map<uint, const TrieNodeInfo*> DagType;

    class Trie
    {

        private:
            TrieNode* _root;
            vector<TrieNodeInfo> _nodeInfoVec;

            bool _initFlag;
            int64_t _freqSum;
            double _minLogFreq;

        public:
            Trie()
            {
                _root = NULL;
                _freqSum = 0;
                _minLogFreq = MAX_DOUBLE;
                _initFlag = false;
            }
            ~Trie()
            {
                dispose();
            }
            bool init()
            {
                if(_getInitFlag())
                {
                    LogError("already initted!");
                    return false;
                }

                try
                {
                    _root = new TrieNode;
                }
                catch(const bad_alloc& e)
                {
                    return false;
                }
                if(NULL == _root)
                {
                    return false;
                }
                _setInitFlag(true);
                return true;
            }
            bool dispose()
            {
                if(!_getInitFlag())
                {
                    return false;
                }
                bool ret = _deleteNode(_root);
                if(!ret)
                {
                    LogFatal("_deleteNode failed!");
                    return false;
                }
                _root = NULL;
                _nodeInfoVec.clear();

                _setInitFlag(false);
                return ret;
            }
            bool loadDict(const char * const filePath)
            {
                assert(_getInitFlag());
                if(!_trieInsert(filePath))
                {
                    LogError("_trieInsert failed.");
                    return false;
                }
                if(!_countWeight())
                {
                    LogError("_countWeight failed.");
                    return false;
                }
                return true;
            }

        private:
            void _setInitFlag(bool on){_initFlag = on;};
            bool _getInitFlag()const{return _initFlag;};

        public:
            const TrieNodeInfo* find(Unicode::const_iterator begin, Unicode::const_iterator end)const
            {

                if(!_getInitFlag())
                {
                    LogFatal("trie not initted!");
                    return NULL;
                }
                if(begin >= end)
                {
                    return NULL;
                }
                TrieNode* p = _root;
                for(Unicode::const_iterator it = begin; it != end; it++)
                {
                    uint16_t chUni = *it;
                    if(p->hmap.find(chUni) == p-> hmap.end())
                    {
                        return NULL;
                    }
                    else
                    {
                        p = p->hmap[chUni];
                    }
                }
                if(p->isLeaf)
                {
                    uint pos = p->nodeInfoVecPos;
                    if(pos < _nodeInfoVec.size())
                    {
                        return &(_nodeInfoVec[pos]);
                    }
                    else
                    {
                        LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
                        return NULL;
                    }
                }
                return NULL;
            }

            bool find(Unicode::const_iterator begin, Unicode::const_iterator end, vector<pair<uint, const TrieNodeInfo*> >& res) const
            {
                if(!_getInitFlag())
                {
                    LogFatal("trie not initted!");
                    return false;
                }
                if (begin >= end)
                {
                    LogFatal("begin >= end");
                    return false;
                }
                TrieNode* p = _root;
                for (Unicode::const_iterator itr = begin; itr != end; itr++)
                {
                    if(p->hmap.find(*itr) == p-> hmap.end())
                    {
                        break;
                    }
                    p = p->hmap[*itr];
                    if(p->isLeaf)
                    {
                        uint pos = p->nodeInfoVecPos;
                        if(pos < _nodeInfoVec.size())
                        {
                            res.push_back(make_pair(itr-begin, &_nodeInfoVec[pos]));
                        }
                        else
                        {
                            LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
                            return false;
                        }
                    }
                }
                return !res.empty();
            }

            bool find(Unicode::const_iterator begin, Unicode::const_iterator end, uint offset, unordered_map<uint, const TrieNodeInfo* > & res) const
            {
                if(!_getInitFlag())
                {
                    LogFatal("trie not initted!");
                    return false;
                }
                if (begin >= end)
                {
                    LogFatal("begin >= end");
                    return false;
                }
                TrieNode* p = _root;
                for (Unicode::const_iterator itr = begin; itr != end; itr++)
                {
                    if(p->hmap.find(*itr) == p-> hmap.end())
                    {
                        break;
                    }
                    p = p->hmap[*itr];
                    if(p->isLeaf)
                    {
                        uint pos = p->nodeInfoVecPos;
                        if(pos < _nodeInfoVec.size())
                        {
                            //res.push_back(make_pair(itr-begin, &_nodeInfoVec[pos]));
                            res[itr-begin + offset] = &_nodeInfoVec[pos];
                        }
                        else
                        {
                            LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
                            return false;
                        }
                    }
                }
                return !res.empty();
            }

        public:
            double getMinLogFreq()const{return _minLogFreq;};

        private:
            bool _insert(const TrieNodeInfo& nodeInfo)
            {
                if(!_getInitFlag())
                {
                    LogFatal("not initted!");
                    return false;
                }

                const Unicode& uintVec = nodeInfo.word;
                TrieNode* p = _root;
                for(uint i = 0; i < uintVec.size(); i++)
                {
                    uint16_t cu = uintVec[i];
                    if(NULL == p)
                    {
                        return false;
                    }
                    if(p->hmap.end() == p->hmap.find(cu))
                    {
                        TrieNode * next = NULL;
                        try
                        {
                            next = new TrieNode;
                        }
                        catch(const bad_alloc& e)
                        {
                            return false;
                        }
                        p->hmap[cu] = next;
                        p = next;
                    }
                    else
                    {
                        p = p->hmap[cu];
                    }
                }
                if(NULL == p)
                {
                    return false;
                }
                if(p->isLeaf)
                {
                    LogError("this node already _inserted");
                    return false;
                }

                p->isLeaf = true;
                _nodeInfoVec.push_back(nodeInfo);
                p->nodeInfoVecPos = _nodeInfoVec.size() - 1;

                return true;
            }

        private:
            bool _trieInsert(const char * const filePath)
            {
                ifstream ifs(filePath);
                if(!ifs)
                {
                    LogError("open %s failed.", filePath);
                    return false;
                }
                string line;
                vector<string> vecBuf;

                TrieNodeInfo nodeInfo;
                while(getline(ifs, line))
                {
                    vecBuf.clear();
                    split(line, vecBuf, " ");
                    if(3 < vecBuf.size())
                    {
                        LogError("line[%s] illegal.", line.c_str());
                        return false;
                    }
                    if(!TransCode::decode(vecBuf[0], nodeInfo.word))
                    {
                        return false;
                    }
                    nodeInfo.freq = atoi(vecBuf[1].c_str());
                    if(3 == vecBuf.size())
                    {
                        nodeInfo.tag = vecBuf[2];
                    }

                    //_insert node
                    if(!_insert(nodeInfo))
                    {
                        LogError("_insert node failed!");
                    }
                }
                return true;
            }
            bool _countWeight()
            {
                if(_nodeInfoVec.empty() || 0 != _freqSum)
                {
                    LogError("_nodeInfoVec is empty or _freqSum has been counted already.");
                    return false;
                }

                //freq total freq
                for(size_t i = 0; i < _nodeInfoVec.size(); i++)
                {
                    _freqSum += _nodeInfoVec[i].freq;
                }

                if(0 == _freqSum)
                {
                    LogError("_freqSum == 0 .");
                    return false;
                }

                //normalize
                for(uint i = 0; i < _nodeInfoVec.size(); i++)
                {
                    TrieNodeInfo& nodeInfo = _nodeInfoVec[i];
                    if(0 == nodeInfo.freq)
                    {
                        LogFatal("nodeInfo.freq == 0!");
                        return false;
                    }
                    nodeInfo.logFreq = log(double(nodeInfo.freq)/double(_freqSum));
                    if(_minLogFreq > nodeInfo.logFreq)
                    {
                        _minLogFreq = nodeInfo.logFreq;
                    }
                }

                return true;
            }

            bool _deleteNode(TrieNode* node)
            {
                for(TrieNodeMap::iterator it = node->hmap.begin(); it != node->hmap.end(); it++)
                {
                    TrieNode* next = it->second;
                    _deleteNode(next);
                }

                delete node;
                return true;
            }

    };
}

#endif
<commit_msg>add logerror<commit_after>/************************************
 * file enc : ASCII
 * author   : wuyanyi09@gmail.com
 ************************************/
#ifndef CPPJIEBA_TRIE_H
#define CPPJIEBA_TRIE_H

#include <iostream>
#include <fstream>
#include <map>
#include <cstring>
#include <stdint.h>
#include <cmath>
#include <limits>
#include "Limonp/str_functs.hpp"
#include "Limonp/logger.hpp"
#include "TransCode.hpp"

namespace CppJieba
{
    using namespace Limonp;
    const double MIN_DOUBLE = -3.14e+100;
    const double MAX_DOUBLE = 3.14e+100;
    typedef unordered_map<uint16_t, struct TrieNode*> TrieNodeMap;
    struct TrieNode
    {
        TrieNodeMap hmap;
        bool isLeaf;
        uint nodeInfoVecPos;
        TrieNode()
        {
            isLeaf = false;
            nodeInfoVecPos = 0;
        }
    };

    struct TrieNodeInfo
    {
        Unicode word;
        size_t freq;
        string tag;
        double logFreq; //logFreq = log(freq/sum(freq));
        TrieNodeInfo():freq(0),logFreq(0.0)
        {
        }
        TrieNodeInfo(const TrieNodeInfo& nodeInfo):word(nodeInfo.word), freq(nodeInfo.freq), tag(nodeInfo.tag), logFreq(nodeInfo.logFreq)
        {
        }
        TrieNodeInfo(const Unicode& _word):word(_word),freq(0),logFreq(MIN_DOUBLE)
        {
        }
        bool operator == (const TrieNodeInfo & rhs) const
        {
            return word == rhs.word && freq == rhs.freq && tag == rhs.tag && abs(logFreq - rhs.logFreq) < 0.001;
        }
    };

    inline ostream& operator << (ostream& os, const TrieNodeInfo & nodeInfo)
    {
        return os << nodeInfo.word << ":" << nodeInfo.freq << ":" << nodeInfo.tag << ":" << nodeInfo.logFreq ;
    }

    typedef unordered_map<uint, const TrieNodeInfo*> DagType;

    class Trie
    {

        private:
            TrieNode* _root;
            vector<TrieNodeInfo> _nodeInfoVec;

            bool _initFlag;
            int64_t _freqSum;
            double _minLogFreq;

        public:
            Trie()
            {
                _root = NULL;
                _freqSum = 0;
                _minLogFreq = MAX_DOUBLE;
                _initFlag = false;
            }
            ~Trie()
            {
                dispose();
            }
            bool init()
            {
                if(_getInitFlag())
                {
                    LogError("already initted!");
                    return false;
                }

                try
                {
                    _root = new TrieNode;
                }
                catch(const bad_alloc& e)
                {
                    return false;
                }
                if(NULL == _root)
                {
                    return false;
                }
                _setInitFlag(true);
                return true;
            }
            bool dispose()
            {
                if(!_getInitFlag())
                {
                    return false;
                }
                bool ret = _deleteNode(_root);
                if(!ret)
                {
                    LogFatal("_deleteNode failed!");
                    return false;
                }
                _root = NULL;
                _nodeInfoVec.clear();

                _setInitFlag(false);
                return ret;
            }
            bool loadDict(const char * const filePath)
            {
                assert(_getInitFlag());
                if(!_trieInsert(filePath))
                {
                    LogError("_trieInsert failed.");
                    return false;
                }
                if(!_countWeight())
                {
                    LogError("_countWeight failed.");
                    return false;
                }
                return true;
            }

        private:
            void _setInitFlag(bool on){_initFlag = on;};
            bool _getInitFlag()const{return _initFlag;};

        public:
            const TrieNodeInfo* find(Unicode::const_iterator begin, Unicode::const_iterator end)const
            {

                if(!_getInitFlag())
                {
                    LogFatal("trie not initted!");
                    return NULL;
                }
                if(begin >= end)
                {
                    return NULL;
                }
                TrieNode* p = _root;
                for(Unicode::const_iterator it = begin; it != end; it++)
                {
                    uint16_t chUni = *it;
                    if(p->hmap.find(chUni) == p-> hmap.end())
                    {
                        return NULL;
                    }
                    else
                    {
                        p = p->hmap[chUni];
                    }
                }
                if(p->isLeaf)
                {
                    uint pos = p->nodeInfoVecPos;
                    if(pos < _nodeInfoVec.size())
                    {
                        return &(_nodeInfoVec[pos]);
                    }
                    else
                    {
                        LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
                        return NULL;
                    }
                }
                return NULL;
            }

            bool find(Unicode::const_iterator begin, Unicode::const_iterator end, vector<pair<uint, const TrieNodeInfo*> >& res) const
            {
                if(!_getInitFlag())
                {
                    LogFatal("trie not initted!");
                    return false;
                }
                if (begin >= end)
                {
                    LogFatal("begin >= end");
                    return false;
                }
                TrieNode* p = _root;
                for (Unicode::const_iterator itr = begin; itr != end; itr++)
                {
                    if(p->hmap.find(*itr) == p-> hmap.end())
                    {
                        break;
                    }
                    p = p->hmap[*itr];
                    if(p->isLeaf)
                    {
                        uint pos = p->nodeInfoVecPos;
                        if(pos < _nodeInfoVec.size())
                        {
                            res.push_back(make_pair(itr-begin, &_nodeInfoVec[pos]));
                        }
                        else
                        {
                            LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
                            return false;
                        }
                    }
                }
                return !res.empty();
            }

            bool find(Unicode::const_iterator begin, Unicode::const_iterator end, uint offset, unordered_map<uint, const TrieNodeInfo* > & res) const
            {
                if(!_getInitFlag())
                {
                    LogFatal("trie not initted!");
                    return false;
                }
                if (begin >= end)
                {
                    LogFatal("begin >= end");
                    return false;
                }
                TrieNode* p = _root;
                for (Unicode::const_iterator itr = begin; itr != end; itr++)
                {
                    if(p->hmap.find(*itr) == p-> hmap.end())
                    {
                        break;
                    }
                    p = p->hmap[*itr];
                    if(p->isLeaf)
                    {
                        uint pos = p->nodeInfoVecPos;
                        if(pos < _nodeInfoVec.size())
                        {
                            //res.push_back(make_pair(itr-begin, &_nodeInfoVec[pos]));
                            res[itr-begin + offset] = &_nodeInfoVec[pos];
                        }
                        else
                        {
                            LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
                            return false;
                        }
                    }
                }
                return !res.empty();
            }

        public:
            double getMinLogFreq()const{return _minLogFreq;};

        private:
            bool _insert(const TrieNodeInfo& nodeInfo)
            {
                if(!_getInitFlag())
                {
                    LogFatal("not initted!");
                    return false;
                }

                const Unicode& uintVec = nodeInfo.word;
                TrieNode* p = _root;
                for(uint i = 0; i < uintVec.size(); i++)
                {
                    uint16_t cu = uintVec[i];
                    if(NULL == p)
                    {
                        return false;
                    }
                    if(p->hmap.end() == p->hmap.find(cu))
                    {
                        TrieNode * next = NULL;
                        try
                        {
                            next = new TrieNode;
                        }
                        catch(const bad_alloc& e)
                        {
                            return false;
                        }
                        p->hmap[cu] = next;
                        p = next;
                    }
                    else
                    {
                        p = p->hmap[cu];
                    }
                }
                if(NULL == p)
                {
                    return false;
                }
                if(p->isLeaf)
                {
                    LogError("this node already _inserted");
                    return false;
                }

                p->isLeaf = true;
                _nodeInfoVec.push_back(nodeInfo);
                p->nodeInfoVecPos = _nodeInfoVec.size() - 1;

                return true;
            }

        private:
            bool _trieInsert(const char * const filePath)
            {
                ifstream ifs(filePath);
                if(!ifs)
                {
                    LogError("open %s failed.", filePath);
                    return false;
                }
                string line;
                vector<string> vecBuf;

                TrieNodeInfo nodeInfo;
                size_t lineno = 0;
                while(getline(ifs, line))
                {
                    vecBuf.clear();
                    lineno ++;
                    split(line, vecBuf, " ");
                    if(3 < vecBuf.size())
                    {
                        LogError("line[%u:%s] illegal.", lineno, line.c_str());
                        return false;
                    }
                    if(!TransCode::decode(vecBuf[0], nodeInfo.word))
                    {
                        LogError("line[%u:%s] illegal.", lineno, line.c_str());
                        return false;
                    }
                    nodeInfo.freq = atoi(vecBuf[1].c_str());
                    if(3 == vecBuf.size())
                    {
                        nodeInfo.tag = vecBuf[2];
                    }

                    //_insert node
                    if(!_insert(nodeInfo))
                    {
                        LogError("_insert node failed!");
                    }
                }
                return true;
            }
            bool _countWeight()
            {
                if(_nodeInfoVec.empty() || 0 != _freqSum)
                {
                    LogError("_nodeInfoVec is empty or _freqSum has been counted already.");
                    return false;
                }

                //freq total freq
                for(size_t i = 0; i < _nodeInfoVec.size(); i++)
                {
                    _freqSum += _nodeInfoVec[i].freq;
                }

                if(0 == _freqSum)
                {
                    LogError("_freqSum == 0 .");
                    return false;
                }

                //normalize
                for(uint i = 0; i < _nodeInfoVec.size(); i++)
                {
                    TrieNodeInfo& nodeInfo = _nodeInfoVec[i];
                    if(0 == nodeInfo.freq)
                    {
                        LogFatal("nodeInfo.freq == 0!");
                        return false;
                    }
                    nodeInfo.logFreq = log(double(nodeInfo.freq)/double(_freqSum));
                    if(_minLogFreq > nodeInfo.logFreq)
                    {
                        _minLogFreq = nodeInfo.logFreq;
                    }
                }

                return true;
            }

            bool _deleteNode(TrieNode* node)
            {
                for(TrieNodeMap::iterator it = node->hmap.begin(); it != node->hmap.end(); it++)
                {
                    TrieNode* next = it->second;
                    _deleteNode(next);
                }

                delete node;
                return true;
            }

    };
}

#endif
<|endoftext|>


<commit_before>#define ENDL "\n"

/*
	struct gl_LightSourceParameters {
		vec4 ambient;
		vec4 diffuse;
		vec4 specular;
		vec4 position;
		vec4 halfVector;
		vec3 spotDirection;
		float spotExponent;
		float spotCutoff; // (range: [0.0,90.0], 180.0)
		float spotCosCutoff; // (range: [1.0,0.0],-1.0)
		float constantAttenuation;
		float linearAttenuation;
		float quadraticAttenuation;
	};

	uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];

	struct gl_LightModelParameters {
		vec4 ambient;
	};

	uniform gl_LightModelParameters gl_LightModel;

	struct gl_MaterialParameters {
		vec4 emission;
		vec4 ambient;
		vec4 diffuse;
		vec4 specular;
		float shininess;
	};

	uniform gl_MaterialParameters gl_FrontMaterial;
	uniform gl_MaterialParameters gl_BackMaterial;
*/

const char* GetVSModelShader()
{
	return
		"varying vec3 vecVertexNormal;"
		"varying vec3 vecLightDir;"
		"varying vec3 vecLightHalf;"
		"varying vec3 vecViewDir;"

		"varying vec4 vecAmbientLight;"
		"varying vec4 vecDiffuseLight;"
		"varying vec4 vecSpecularLight;"

		"void main()"
		"{"
		"	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"

		"	vecVertexNormal = normalize(gl_NormalMatrix * gl_Normal);"
		"	vecLightDir = normalize(gl_LightSource[0].position.xyz);"
		"	vecLightHalf = gl_LightSource[0].halfVector.xyz;"
		"	vecViewDir = normalize(-vec3(gl_ModelViewMatrix * gl_Vertex));"

		"	vecAmbientLight = gl_FrontMaterial.emission + gl_FrontMaterial.ambient * gl_LightModel.ambient + gl_LightSource[0].ambient * gl_FrontMaterial.ambient;"
		"	vecDiffuseLight = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse;"
		"	vecSpecularLight = gl_LightSource[0].specular * gl_FrontMaterial.specular;"

		"	gl_TexCoord[0] = gl_MultiTexCoord0;"
		"}";
}

const char* GetFSModelShader()
{
	return
		"varying vec3 vecVertexNormal;"
		"varying vec3 vecLightDir;"
		"varying vec3 vecLightHalf;"
		"varying vec3 vecViewDir;"

		"varying vec4 vecAmbientLight;"
		"varying vec4 vecDiffuseLight;"
		"varying vec4 vecSpecularLight;"

		"uniform sampler2D iDiffuseTexture;"
		"uniform sampler2D iNormalMap;"
		"uniform sampler2D iAOMap;"
		"uniform sampler2D iCAOMap;"

		"uniform bool bLighting;"
		"uniform bool bDiffuseTexture;"
		"uniform bool bNormalMap;"
		"uniform bool bAOMap;"
		"uniform bool bCAOMap;"

		"mat3 ComputeTangentFrame(vec3 vecNormal, vec3 vecPosition, vec2 vecTexCoord)"
		"{"
		"	vec3 dpx = dFdx(vecPosition);"
		"	vec3 dpy = dFdy(vecPosition);"
		"	vec2 dtx = dFdx(vecTexCoord);"
		"	vec2 dty = dFdy(vecTexCoord);"

		"	vec3 vecTangent = normalize(dpx * dty.t - dpy * dtx.t);"
		"	vec3 vecBitangent = cross(vecTangent, vecNormal);"

		"	return mat3(vecTangent, vecBitangent, vecNormal);"
		"}"

		"void main()"
		"{"
		"	vec4 clrDiffuseColor = vec4(1.0, 1.0, 1.0, 1.0);"
		"	vec3 vecTangentNormal;"
		"	vec4 clrAO = vec4(1.0, 1.0, 1.0, 1.0);"
		"	vec4 clrCAO = vec4(1.0, 1.0, 1.0, 1.0);"
		"	vec4 clrLight;"

		"	if (bDiffuseTexture)"
		"		clrDiffuseColor = texture2D(iDiffuseTexture, gl_TexCoord[0].xy);"

		"	if (bNormalMap)"
		"	{"
		"		vecTangentNormal = normalize(texture2D(iNormalMap, gl_TexCoord[0].xy).xyz * 2.0 - 1.0);"
		"		vecTangentNormal.x = -vecTangentNormal.x;"
		"	}"

		"	if (bAOMap)"
		"		clrAO = texture2D(iAOMap, gl_TexCoord[0].xy);"

		"	if (bCAOMap)"
		"		clrCAO = texture2D(iCAOMap, gl_TexCoord[0].xy);"

		"	if (bLighting)"
		"	{"
		"		vec3 vecTranslatedNormal = vecTangentNormal;"

		"		if (bNormalMap)"
		"		{"
		"			mat3 mTBN = ComputeTangentFrame(normalize(vecVertexNormal), normalize(vecViewDir), gl_TexCoord[0].st);"
		"			vecTranslatedNormal = mTBN * vecTangentNormal;"
		"		}"
		"		else"
		"			vecTranslatedNormal = normalize(vecVertexNormal);"

		"		float flLightStrength = dot(vecTranslatedNormal, vecLightDir);"
		"		if (flLightStrength < 0.0) flLightStrength = 0.0;"
		"		if (flLightStrength > 1.0) flLightStrength = 1.0;"

		"		float flNormalDotHalfVector = min(0.0, dot(vecTranslatedNormal, normalize(vecLightHalf)));"

		"		float flPowerFactor = 0.0;"
		"		if (flLightStrength > 0.0)"
		"			flPowerFactor = pow(flNormalDotHalfVector, gl_FrontMaterial.shininess);"

		"		clrLight = vecAmbientLight +"
		"			vecDiffuseLight * flLightStrength +"
		"			vecSpecularLight * flPowerFactor;"
		"	}"
		"	else"
		"	{"
		"		float flDot = dot(normalize(vecVertexNormal), vec3(0, 1, 0));"
		"		clrLight = vec4(1, 1, 1, 1) * (flDot * 0.5) + vec4(0.45, 0.45, 0.45, 0.45);"
		"		clrLight = clrLight * gl_FrontMaterial.diffuse;"
		"	}"

		"	gl_FragColor = clrLight * clrDiffuseColor * clrAO * clrCAO;"

		"	gl_FragColor.a = clrDiffuseColor.a;"
		"}";
}

const char* GetVSFlattenedShadowMap()
{
	return
		"varying vec4 vecShadowCoord;"
		"varying vec3 vecSurfaceNormal;"

		"void main()"
		"{"
		"	vecShadowCoord = gl_TextureMatrix[7] * gl_Vertex;"
		"	vecSurfaceNormal = gl_Normal;"
		"	gl_Position = gl_MultiTexCoord0;"
		"	gl_FrontColor = gl_Color;"
		"}";
}

const char* GetFSFlattenedShadowMap()
{
	return
		"uniform sampler2D iShadowMap;"
		"uniform vec3 vecLightNormal;"
		"uniform bool bOccludeAll;"
		"varying vec4 vecShadowCoord;"
		"varying vec3 vecSurfaceNormal;"

		"void main()"
		"{"
		"	float flLightDot = dot(vecLightNormal, normalize(vecSurfaceNormal));"

			// If the face is facing away from the light source, don't include it in the sample.
		"	if (flLightDot > 0.0)"
		"	{"
		"		gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);"
		"	}"
		"	else"
		"	{"
		"		float flShadow = 1.0;"
		"		if (bOccludeAll)"
		"			flShadow = 0.0;"
		"		else if (vecShadowCoord.w > 0.0)"
		"		{"
		"			vec4 vecShadowCoordinateWdivide = vecShadowCoord / vecShadowCoord.w;"
		"			float flDistanceFromLight = texture2D(iShadowMap, vecShadowCoordinateWdivide.st).z;"

					// Reduce moire and self-shadowing
		"			vecShadowCoordinateWdivide.z -= 0.003 + 0.004*(1.0-flLightDot);"	// Use flLightDot to get further away from surfaces at high angles.

					// It's .99 because sometimes if every sample on a point is perfectly white it suffers integer overflow down the line and becomes black.
		"			flShadow = flDistanceFromLight < vecShadowCoordinateWdivide.z?0.0:0.99;"
		"		}"

		"		gl_FragColor = vec4(flShadow, flShadow, flShadow, 1.0);"
		"	}"
		"}";
}

const char* GetVSAOMap()
{
	return
		"varying vec2 vecUV;"

		"void main()"
		"{"
		"	gl_Position = ftransform();"
		"	gl_FrontColor = gl_Color;"
		"	vecUV = gl_MultiTexCoord0.st;"
		"}";
}

const char* GetFSAOMap()
{
	return
		"uniform sampler2D iAOMap;"
		"varying vec2 vecUV;"

		"void main()"
		"{"
		"	vec4 vecColor = texture2D(iAOMap, vecUV);"
		"	if (vecColor.a == 0.0)"	// No samples
		"		gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);"
		"	else"
		"		gl_FragColor = vec4(vecColor.x/vecColor.a, vecColor.y/vecColor.a, vecColor.z/vecColor.a, 1.0);"
		"}";
}
<commit_msg>Fixed specular not showing up and sometimes causing artifacts.<commit_after>#define ENDL "\n"

/*
	struct gl_LightSourceParameters {
		vec4 ambient;
		vec4 diffuse;
		vec4 specular;
		vec4 position;
		vec4 halfVector;
		vec3 spotDirection;
		float spotExponent;
		float spotCutoff; // (range: [0.0,90.0], 180.0)
		float spotCosCutoff; // (range: [1.0,0.0],-1.0)
		float constantAttenuation;
		float linearAttenuation;
		float quadraticAttenuation;
	};

	uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];

	struct gl_LightModelParameters {
		vec4 ambient;
	};

	uniform gl_LightModelParameters gl_LightModel;

	struct gl_MaterialParameters {
		vec4 emission;
		vec4 ambient;
		vec4 diffuse;
		vec4 specular;
		float shininess;
	};

	uniform gl_MaterialParameters gl_FrontMaterial;
	uniform gl_MaterialParameters gl_BackMaterial;
*/

const char* GetVSModelShader()
{
	return
		"varying vec3 vecVertexNormal;"
		"varying vec3 vecLightDir;"
		"varying vec3 vecLightHalf;"
		"varying vec3 vecViewDir;"

		"varying vec4 vecAmbientLight;"
		"varying vec4 vecDiffuseLight;"
		"varying vec4 vecSpecularLight;"

		"void main()"
		"{"
		"	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"

		"	vecVertexNormal = normalize(gl_NormalMatrix * gl_Normal);"
		"	vecLightDir = normalize(gl_LightSource[0].position.xyz);"
		"	vecLightHalf = gl_LightSource[0].halfVector.xyz;"
		"	vecViewDir = normalize(-vec3(gl_ModelViewMatrix * gl_Vertex));"

		"	vecAmbientLight = gl_FrontMaterial.emission + gl_FrontMaterial.ambient * gl_LightModel.ambient + gl_LightSource[0].ambient * gl_FrontMaterial.ambient;"
		"	vecDiffuseLight = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse;"
		"	vecSpecularLight = gl_LightSource[0].specular * gl_FrontMaterial.specular;"

		"	gl_TexCoord[0] = gl_MultiTexCoord0;"
		"}";
}

const char* GetFSModelShader()
{
	return
		"varying vec3 vecVertexNormal;"
		"varying vec3 vecLightDir;"
		"varying vec3 vecLightHalf;"
		"varying vec3 vecViewDir;"

		"varying vec4 vecAmbientLight;"
		"varying vec4 vecDiffuseLight;"
		"varying vec4 vecSpecularLight;"

		"uniform sampler2D iDiffuseTexture;"
		"uniform sampler2D iNormalMap;"
		"uniform sampler2D iAOMap;"
		"uniform sampler2D iCAOMap;"

		"uniform bool bLighting;"
		"uniform bool bDiffuseTexture;"
		"uniform bool bNormalMap;"
		"uniform bool bAOMap;"
		"uniform bool bCAOMap;"

		"mat3 ComputeTangentFrame(vec3 vecNormal, vec3 vecPosition, vec2 vecTexCoord)"
		"{"
		"	vec3 dpx = dFdx(vecPosition);"
		"	vec3 dpy = dFdy(vecPosition);"
		"	vec2 dtx = dFdx(vecTexCoord);"
		"	vec2 dty = dFdy(vecTexCoord);"

		"	vec3 vecTangent = normalize(dpx * dty.t - dpy * dtx.t);"
		"	vec3 vecBitangent = cross(vecTangent, vecNormal);"

		"	return mat3(vecTangent, vecBitangent, vecNormal);"
		"}"

		"void main()"
		"{"
		"	vec4 clrDiffuseColor = vec4(1.0, 1.0, 1.0, 1.0);"
		"	vec3 vecTangentNormal;"
		"	vec4 clrAO = vec4(1.0, 1.0, 1.0, 1.0);"
		"	vec4 clrCAO = vec4(1.0, 1.0, 1.0, 1.0);"
		"	vec4 clrLight;"

		"	if (bDiffuseTexture)"
		"		clrDiffuseColor = texture2D(iDiffuseTexture, gl_TexCoord[0].xy);"

		"	if (bNormalMap)"
		"	{"
		"		vecTangentNormal = normalize(texture2D(iNormalMap, gl_TexCoord[0].xy).xyz * 2.0 - 1.0);"
		"		vecTangentNormal.x = -vecTangentNormal.x;"
		"	}"

		"	if (bAOMap)"
		"		clrAO = texture2D(iAOMap, gl_TexCoord[0].xy);"

		"	if (bCAOMap)"
		"		clrCAO = texture2D(iCAOMap, gl_TexCoord[0].xy);"

		"	if (bLighting)"
		"	{"
		"		vec3 vecTranslatedNormal = vecTangentNormal;"

		"		if (bNormalMap)"
		"		{"
		"			mat3 mTBN = ComputeTangentFrame(normalize(vecVertexNormal), normalize(vecViewDir), gl_TexCoord[0].st);"
		"			vecTranslatedNormal = mTBN * vecTangentNormal;"
		"		}"
		"		else"
		"			vecTranslatedNormal = normalize(vecVertexNormal);"

		"		float flLightStrength = dot(vecTranslatedNormal, vecLightDir);"
		"		if (flLightStrength < 0.0) flLightStrength = 0.0;"
		"		if (flLightStrength > 1.0) flLightStrength = 1.0;"

		"		float flNormalDotHalfVector = max(0.0, dot(vecTranslatedNormal, normalize(vecLightHalf)));"

		"		float flPowerFactor = 0.0;"
		"		if (flLightStrength > 0.0)"
		"			flPowerFactor = pow(flNormalDotHalfVector, gl_FrontMaterial.shininess);"

		"		clrLight = vecAmbientLight +"
		"			vecDiffuseLight * flLightStrength +"
		"			vecSpecularLight * flPowerFactor;"
		"	}"
		"	else"
		"	{"
		"		float flDot = dot(normalize(vecVertexNormal), vec3(0, 1, 0));"
		"		clrLight = vec4(1, 1, 1, 1) * (flDot * 0.5) + vec4(0.45, 0.45, 0.45, 0.45);"
		"		clrLight = clrLight * gl_FrontMaterial.diffuse;"
		"	}"

		"	gl_FragColor = clrLight * clrDiffuseColor * clrAO * clrCAO;"

		"	gl_FragColor.a = clrDiffuseColor.a;"
		"}";
}

const char* GetVSFlattenedShadowMap()
{
	return
		"varying vec4 vecShadowCoord;"
		"varying vec3 vecSurfaceNormal;"

		"void main()"
		"{"
		"	vecShadowCoord = gl_TextureMatrix[7] * gl_Vertex;"
		"	vecSurfaceNormal = gl_Normal;"
		"	gl_Position = gl_MultiTexCoord0;"
		"	gl_FrontColor = gl_Color;"
		"}";
}

const char* GetFSFlattenedShadowMap()
{
	return
		"uniform sampler2D iShadowMap;"
		"uniform vec3 vecLightNormal;"
		"uniform bool bOccludeAll;"
		"varying vec4 vecShadowCoord;"
		"varying vec3 vecSurfaceNormal;"

		"void main()"
		"{"
		"	float flLightDot = dot(vecLightNormal, normalize(vecSurfaceNormal));"

			// If the face is facing away from the light source, don't include it in the sample.
		"	if (flLightDot > 0.0)"
		"	{"
		"		gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);"
		"	}"
		"	else"
		"	{"
		"		float flShadow = 1.0;"
		"		if (bOccludeAll)"
		"			flShadow = 0.0;"
		"		else if (vecShadowCoord.w > 0.0)"
		"		{"
		"			vec4 vecShadowCoordinateWdivide = vecShadowCoord / vecShadowCoord.w;"
		"			float flDistanceFromLight = texture2D(iShadowMap, vecShadowCoordinateWdivide.st).z;"

					// Reduce moire and self-shadowing
		"			vecShadowCoordinateWdivide.z -= 0.003 + 0.004*(1.0-flLightDot);"	// Use flLightDot to get further away from surfaces at high angles.

					// It's .99 because sometimes if every sample on a point is perfectly white it suffers integer overflow down the line and becomes black.
		"			flShadow = flDistanceFromLight < vecShadowCoordinateWdivide.z?0.0:0.99;"
		"		}"

		"		gl_FragColor = vec4(flShadow, flShadow, flShadow, 1.0);"
		"	}"
		"}";
}

const char* GetVSAOMap()
{
	return
		"varying vec2 vecUV;"

		"void main()"
		"{"
		"	gl_Position = ftransform();"
		"	gl_FrontColor = gl_Color;"
		"	vecUV = gl_MultiTexCoord0.st;"
		"}";
}

const char* GetFSAOMap()
{
	return
		"uniform sampler2D iAOMap;"
		"varying vec2 vecUV;"

		"void main()"
		"{"
		"	vec4 vecColor = texture2D(iAOMap, vecUV);"
		"	if (vecColor.a == 0.0)"	// No samples
		"		gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);"
		"	else"
		"		gl_FragColor = vec4(vecColor.x/vecColor.a, vecColor.y/vecColor.a, vecColor.z/vecColor.a, 1.0);"
		"}";
}
<|endoftext|>


<commit_before>#include "Util.h"

std::string strToUpper(const char* from)
{
	std::string str(from);
	for(unsigned int i = 0; i < str.size(); i++)
		str[i] = toupper(from[i]);
	return str;
}

std::string& strToUpper(std::string& str)
{
	for(unsigned int i = 0; i < str.size(); i++)
		str[i] = toupper(str[i]);

	return str;
}

std::string strToUpper(const std::string& str)
{
	return strToUpper(str.c_str());
}

float round(float num)
{
	return (float)((int)(num + 0.5f));
}

Eigen::Affine3f& roundMatrix(Eigen::Affine3f& mat)
{
	mat.translation()[0] = round(mat.translation()[0]);
	mat.translation()[1] = round(mat.translation()[1]);
	return mat;
}

Eigen::Affine3f roundMatrix(const Eigen::Affine3f& mat)
{
	Eigen::Affine3f ret = mat;
	roundMatrix(ret);
	return ret;
}

Eigen::Vector3f roundVector(const Eigen::Vector3f& vec)
{
	Eigen::Vector3f ret = vec;
	ret[0] = round(ret[0]);
	ret[1] = round(ret[1]);
	ret[2] = round(ret[2]);
	return ret;
}

Eigen::Vector2f roundVector(const Eigen::Vector2f& vec)
{
	Eigen::Vector2f ret = vec;
	ret[0] = round(ret[0]);
	ret[1] = round(ret[1]);
	return ret;
}
<commit_msg>Fix for building with VS2013.<commit_after>#include "Util.h"

std::string strToUpper(const char* from)
{
	std::string str(from);
	for(unsigned int i = 0; i < str.size(); i++)
		str[i] = toupper(from[i]);
	return str;
}

std::string& strToUpper(std::string& str)
{
	for(unsigned int i = 0; i < str.size(); i++)
		str[i] = toupper(str[i]);

	return str;
}

std::string strToUpper(const std::string& str)
{
	return strToUpper(str.c_str());
}

#if _MSC_VER < 1800
float round(float num)
{
	return (float)((int)(num + 0.5f));
}
#endif

Eigen::Affine3f& roundMatrix(Eigen::Affine3f& mat)
{
	mat.translation()[0] = round(mat.translation()[0]);
	mat.translation()[1] = round(mat.translation()[1]);
	return mat;
}

Eigen::Affine3f roundMatrix(const Eigen::Affine3f& mat)
{
	Eigen::Affine3f ret = mat;
	roundMatrix(ret);
	return ret;
}

Eigen::Vector3f roundVector(const Eigen::Vector3f& vec)
{
	Eigen::Vector3f ret = vec;
	ret[0] = round(ret[0]);
	ret[1] = round(ret[1]);
	ret[2] = round(ret[2]);
	return ret;
}

Eigen::Vector2f roundVector(const Eigen::Vector2f& vec)
{
	Eigen::Vector2f ret = vec;
	ret[0] = round(ret[0]);
	ret[1] = round(ret[1]);
	return ret;
}
<|endoftext|>