<commit_before>// Copyright (c) 2022 The Orbit 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 <gtest/gtest.h>

#include <random>

#include "GlCanvas.h"
#include "MockBatcher.h"
#include "MockTextRenderer.h"
#include "MockTimelineInfo.h"
#include "TimelineUi.h"
#include "Viewport.h"

namespace orbit_gl {

class TimelineUiTest : public TimelineUi {
 public:
  static constexpr int kBigScreenPixelsWidth = 2000;
  static constexpr int kSmallScreenMaxPixelsWidth = 700;
  static constexpr int kTinyScreenMaxPixelsWidth = 200;

  explicit TimelineUiTest(MockTimelineInfo* mock_timeline_info, Viewport* viewport,
                          TimeGraphLayout* layout)
      : TimelineUi(nullptr /*parent*/, mock_timeline_info, viewport, layout),
        primitive_assembler_(&mock_batcher_),
        viewport_(viewport),
        mock_timeline_info_(mock_timeline_info) {
    viewport->SetWorldSize(viewport->GetWorldWidth(), TimelineUi::GetHeight());
  }

  void TestUpdatePrimitives(uint64_t min_tick, uint64_t max_tick) {
    mock_text_renderer_.Clear();
    mock_batcher_.ResetElements();
    mock_timeline_info_->SetMinMax(min_tick, max_tick);

    UpdatePrimitives(primitive_assembler_, mock_text_renderer_, min_tick, max_tick,
                     PickingMode::kNone);

    int num_labels = mock_text_renderer_.GetNumAddTextCalls();
    int num_boxes = mock_batcher_.GetNumBoxes();
    int num_major_ticks = mock_batcher_.GetNumLinesByColor(kTimelineMajorTickColor);
    int num_minor_ticks = mock_batcher_.GetNumLinesByColor(kTimelineMinorTickColor);

    // Lines should be only major and minor ticks.
    EXPECT_EQ(mock_batcher_.GetNumLines(), num_major_ticks + num_minor_ticks);

    // Major ticks should always be between 2 and 10, given scale set. In extremely small screens
    // (Width < 200), we don't force a minimum number of major ticks.
    if (viewport_->GetWorldWidth() > kTinyScreenMaxPixelsWidth) {
      EXPECT_GE(num_major_ticks, 2);
    }
    EXPECT_LE(num_major_ticks, 10);

    // Depending on the scale, there should be 1 minor ticks or 4 between each major tick, which
    // means that (calling MT to the number of major ticks, and mt to the number of minor ticks)
    // mt is between (MT-1, MT+1) or mt is between (4x(MT-1), 4x(MT+1)).
    EXPECT_GE(num_minor_ticks, num_major_ticks - 1);
    EXPECT_LE(num_minor_ticks, 4 * (num_major_ticks + 1));
    EXPECT_THAT(num_minor_ticks, testing::AnyOf(testing::Le(num_major_ticks + 1),
                                                testing::Ge(4 * (num_major_ticks - 1))));

    // Labels should all have the same number of digits, start at the same vertical position and
    // they will appear at the right of each major tick.
    EXPECT_TRUE(mock_text_renderer_.HasAddTextsSameLength());
    EXPECT_TRUE(mock_text_renderer_.AreAddTextsAlignedVertically());

    // TODO(b/218311326): In some cases, small screens (Width < 700) failed in the condition between
    // #labels and #major_ticks, since we are drawing major_ticks anyways when labels intersect.
    if (viewport_->GetWorldWidth() > kSmallScreenMaxPixelsWidth) {
      EXPECT_GE(num_labels, num_major_ticks - 1);
    }
    EXPECT_LE(num_labels, num_major_ticks + 1);

    // Boxes: One box per each label + Background box + margin box.
    EXPECT_EQ(num_boxes, num_labels + 2);

    // Everything should be between kZValueTimeBar and kZValueTimeBarMouseLabel.
    EXPECT_TRUE(mock_text_renderer_.IsTextBetweenZLayers(GlCanvas::kZValueTimeBar,
                                                         GlCanvas::kZValueTimeBarMouseLabel));
    EXPECT_TRUE(mock_batcher_.IsEverythingBetweenZLayers(GlCanvas::kZValueTimeBar,
                                                         GlCanvas::kZValueTimeBarMouseLabel));
  }

 private:
  MockBatcher mock_batcher_;
  MockTextRenderer mock_text_renderer_;
  PrimitiveAssembler primitive_assembler_;
  Viewport* viewport_;
  MockTimelineInfo* mock_timeline_info_;
};

static void TestUpdatePrimitivesWithSeveralRanges(int world_width) {
  MockTimelineInfo mock_timeline_info;
  mock_timeline_info.SetWorldWidth(world_width);

  TimeGraphLayout layout;
  Viewport viewport(world_width, 0);
  TimelineUiTest timeline_ui_test(&mock_timeline_info, &viewport, &layout);
  timeline_ui_test.TestUpdatePrimitives(0, 100);
  timeline_ui_test.TestUpdatePrimitives(1'000'000'000, 1'000'000'100);
  timeline_ui_test.TestUpdatePrimitives(0, 999'999'000);
  timeline_ui_test.TestUpdatePrimitives(0, 999'999'999);
  timeline_ui_test.TestUpdatePrimitives(0, 1'000'000'000);

  // Maximum supported timestamp: 1 Month.
  std::mt19937 gen;
  std::uniform_int_distribution<> distrib(0, kNanosecondsPerMonth);

  for (int i = 0; i < 100; i++) {
    uint64_t timestamp_1 = distrib(gen);
    uint64_t timestamp_2 = distrib(gen);
    timeline_ui_test.TestUpdatePrimitives(std::min(timestamp_1, timestamp_2),
                                          std::max(timestamp_1, timestamp_2));
  }
}

TEST(TimelineUI, UpdatePrimitives) {
  TestUpdatePrimitivesWithSeveralRanges(TimelineUiTest::kBigScreenPixelsWidth);
  TestUpdatePrimitivesWithSeveralRanges(TimelineUiTest::kTinyScreenMaxPixelsWidth);
}

}  // namespace orbit_gl<commit_msg>Fix timeline's visual tests (#3625)<commit_after>// Copyright (c) 2022 The Orbit 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 <gtest/gtest.h>

#include <random>

#include "GlCanvas.h"
#include "MockBatcher.h"
#include "MockTextRenderer.h"
#include "MockTimelineInfo.h"
#include "TimelineUi.h"
#include "Viewport.h"

namespace orbit_gl {

class TimelineUiTest : public TimelineUi {
 public:
  static constexpr int kBigScreenPixelsWidth = 2000;
  static constexpr int kSmallScreenMaxPixelsWidth = 700;
  static constexpr int kTinyScreenMaxPixelsWidth = 200;

  explicit TimelineUiTest(MockTimelineInfo* mock_timeline_info, Viewport* viewport,
                          TimeGraphLayout* layout)
      : TimelineUi(nullptr /*parent*/, mock_timeline_info, viewport, layout),
        primitive_assembler_(&mock_batcher_),
        viewport_(viewport),
        mock_timeline_info_(mock_timeline_info) {
    viewport->SetWorldSize(viewport->GetWorldWidth(), TimelineUi::GetHeight());
  }

  void TestUpdatePrimitives(uint64_t min_tick, uint64_t max_tick) {
    mock_text_renderer_.Clear();
    mock_batcher_.ResetElements();
    mock_timeline_info_->SetMinMax(min_tick, max_tick);

    UpdatePrimitives(primitive_assembler_, mock_text_renderer_, min_tick, max_tick,
                     PickingMode::kNone);

    int num_labels = mock_text_renderer_.GetNumAddTextCalls();
    int num_boxes = mock_batcher_.GetNumBoxes();
    int num_major_ticks = mock_batcher_.GetNumLinesByColor(kTimelineMajorTickColor);
    int num_minor_ticks = mock_batcher_.GetNumLinesByColor(kTimelineMinorTickColor);

    // Lines should be only major and minor ticks.
    EXPECT_EQ(mock_batcher_.GetNumLines(), num_major_ticks + num_minor_ticks);

    // Major ticks should always be between 2 and 10, given scale set. In extremely small screens
    // (Width < 200), we don't force a minimum number of major ticks.
    if (viewport_->GetWorldWidth() > kTinyScreenMaxPixelsWidth) {
      EXPECT_GE(num_major_ticks, 2);
    }
    EXPECT_LE(num_major_ticks, 10);

    // Depending on the scale, there should be 1, 2 or 4 minor ticks between each major tick, which
    // means that (calling MT to the number of major ticks, and mt to the number of minor ticks)
    // mt is between (MT-1, MT+1), (2*(MT-1), 2*(MT+1)) or (4*(MT-1), 4*(MT+1)).
    EXPECT_GE(num_minor_ticks, num_major_ticks - 1);
    EXPECT_LE(num_minor_ticks, 4 * (num_major_ticks + 1));
    EXPECT_THAT(num_minor_ticks,
                testing::AnyOf(testing::Le(num_major_ticks + 1),
                               testing::AllOf(testing::Ge(2 * (num_major_ticks - 1)),
                                              testing::Le(2 * (num_major_ticks + 1))),
                               testing::Ge(4 * (num_major_ticks - 1))));

    // Generally, labels should all have the same number of digits, start at the same vertical
    // position and they will appear at the right of each major tick. The only exception is about
    // labels with the same number of digits when the number of hours is greater than 100. The hour
    // part of the iso timestamp will have 2 digits when it's smaller than 100.
    if (max_tick < 100 * kNanosecondsPerHour) {
      EXPECT_TRUE(mock_text_renderer_.HasAddTextsSameLength());
    }
    EXPECT_TRUE(mock_text_renderer_.AreAddTextsAlignedVertically());

    // TODO(b/218311326): In some cases, small screens (Width < 700) failed in the condition between
    // #labels and #major_ticks, since we are drawing major_ticks anyways when labels intersect.
    if (viewport_->GetWorldWidth() > kSmallScreenMaxPixelsWidth) {
      EXPECT_GE(num_labels, num_major_ticks - 1);
    }
    EXPECT_LE(num_labels, num_major_ticks + 1);

    // Boxes: One box per each label + Background box + margin box.
    EXPECT_EQ(num_boxes, num_labels + 2);

    // Everything should be between kZValueTimeBar and kZValueTimeBarMouseLabel.
    EXPECT_TRUE(mock_text_renderer_.IsTextBetweenZLayers(GlCanvas::kZValueTimeBar,
                                                         GlCanvas::kZValueTimeBarMouseLabel));
    EXPECT_TRUE(mock_batcher_.IsEverythingBetweenZLayers(GlCanvas::kZValueTimeBar,
                                                         GlCanvas::kZValueTimeBarMouseLabel));
  }

 private:
  MockBatcher mock_batcher_;
  MockTextRenderer mock_text_renderer_;
  PrimitiveAssembler primitive_assembler_;
  Viewport* viewport_;
  MockTimelineInfo* mock_timeline_info_;
};

static void TestUpdatePrimitivesWithSeveralRanges(int world_width) {
  MockTimelineInfo mock_timeline_info;
  mock_timeline_info.SetWorldWidth(world_width);

  TimeGraphLayout layout;
  Viewport viewport(world_width, 0);
  TimelineUiTest timeline_ui_test(&mock_timeline_info, &viewport, &layout);
  timeline_ui_test.TestUpdatePrimitives(0, 100);
  timeline_ui_test.TestUpdatePrimitives(kNanosecondsPerSecond, kNanosecondsPerSecond + 100);
  timeline_ui_test.TestUpdatePrimitives(0, kNanosecondsPerSecond - 100);
  timeline_ui_test.TestUpdatePrimitives(0, kNanosecondsPerSecond - 1);
  timeline_ui_test.TestUpdatePrimitives(0, kNanosecondsPerSecond);
  timeline_ui_test.TestUpdatePrimitives(0, 59 * kNanosecondsPerMinute);
  timeline_ui_test.TestUpdatePrimitives(90 * kNanosecondsPerHour, 100 * kNanosecondsPerHour);

  // Maximum supported timestamp: 1 Month.
  std::mt19937 gen;
  std::uniform_int_distribution<uint64_t> distrib(0, kNanosecondsPerMonth);

  for (int i = 0; i < 100; i++) {
    uint64_t timestamp_1 = distrib(gen);
    uint64_t timestamp_2 = distrib(gen);
    timeline_ui_test.TestUpdatePrimitives(std::min(timestamp_1, timestamp_2),
                                          std::max(timestamp_1, timestamp_2));
  }
}

TEST(TimelineUI, UpdatePrimitives) {
  TestUpdatePrimitivesWithSeveralRanges(TimelineUiTest::kBigScreenPixelsWidth);
  TestUpdatePrimitivesWithSeveralRanges(TimelineUiTest::kTinyScreenMaxPixelsWidth);
}

}  // namespace orbit_gl<|endoftext|>


<commit_before><commit_msg>Fixed getSemanticSortedColumn for both modes: zoom and grid<commit_after><|endoftext|>


<commit_before><commit_msg>getSortedColumns aware of hideColumns option active or not<commit_after><|endoftext|>


<commit_before>//

// RemotePhotoTool - remote camera control software

// Copyright (C) 2008-2018 Michael Fink

//

/// \file Location\stdafx.cpp Precompiled header support

//

// includes

#include "stdafx.h"

<commit_msg>converted file from UTF-16 to UTF-8; cppcheck reported an error<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2018 Michael Fink
//
/// \file Location\stdafx.cpp Precompiled header support
//

// includes
#include "stdafx.h"
<|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2013 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Teapotnet.                                     *
 *                                                                       *
 *   Teapotnet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   Teapotnet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with Teapotnet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#ifndef TPN_INCLUDE_H
#define TPN_INCLUDE_H

//#define DEBUG			1
#define APPNAME			"Teapotnet"
#define APPVERSION		"0.9.5"
#define APPMAGIC		 0x54504f54 // "TPOT"
#define APPAUTHOR		"Paul-Louis Ageneau"
#define APPLINK			"https://teapotnet.org/"
#define SOURCELINK		"https://teapotnet.org/source"
#define HELPLINK		"https://teapotnet.org/help"
#define DOWNLOADURL		"https://teapotnet.org/download"
#define BUGSLINK		"mailto:bugs@teapotnet.org"

#include "pla/include.hpp"
#include "pla/string.hpp"
#include "pla/binarystring.hpp"

using namespace pla;

namespace tpn
{
	typedef BinaryString Identifier;
	typedef std::pair<Identifier, Identifier> IdentifierPair;
}

#endif

<commit_msg>Version 0.10.1<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2013 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Teapotnet.                                     *
 *                                                                       *
 *   Teapotnet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   Teapotnet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with Teapotnet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#ifndef TPN_INCLUDE_H
#define TPN_INCLUDE_H

//#define DEBUG			1
#define APPNAME			"Teapotnet"
#define APPVERSION		"0.10.1"
#define APPMAGIC		 0x54504f54 // "TPOT"
#define APPAUTHOR		"Paul-Louis Ageneau"
#define APPLINK			"https://teapotnet.org/"
#define SOURCELINK		"https://teapotnet.org/source"
#define HELPLINK		"https://teapotnet.org/help"
#define DOWNLOADURL		"https://teapotnet.org/download"
#define BUGSLINK		"mailto:bugs@teapotnet.org"

#include "pla/include.hpp"
#include "pla/string.hpp"
#include "pla/binarystring.hpp"

using namespace pla;

namespace tpn
{
	typedef BinaryString Identifier;
	typedef std::pair<Identifier, Identifier> IdentifierPair;
}

#endif

<|endoftext|>


<commit_before>#ifndef HMLIB_TYPETRAITS_INC
#define HMLIB_TYPETRAITS_INC 100
#
#include<type_traits>
#include<iterator>
namespace hmLib{
	template<typename type1, typename type2>
	struct select_derived{
		template<typename type, bool Type1IsBase = std::is_base_of<type1,type2>::value, bool Type2IsBase = std::is_base_of<type2, type1>::value>
		struct check{
			using ans_type = void;
		};
		template<typename type>
		struct check<type, true, false>{
			using ans_type = type2;
		};
		template<typename type>
		struct check<type, false, true>{
			using ans_type = type1;
		};
		using type = typename check<void>::ans_type;
	};
	template<typename terget, typename... others>
	struct near_base_of{
		template<typename terget_, typename candidate_>
		struct check{
			using ans_type = candidate_;
		};
		using type = typename check<terget, void>::ans_type;
	};
	template<typename terget, typename try_type, typename... others>
	struct near_base_of<terget, try_type, others...>{
		template<typename terget_, typename candidate_, bool IsBase = std::is_base_of<try_type, terget>::value>
		struct check{
			using ans_type = typename near_base_of<terget, others...>::template check<terget_, candidate_>::ans_type;
		};
		template<typename terget_, typename candidate_>
		struct check<terget_, candidate_, true>{
			using new_candidate = typename select_derived<candidate_, try_type>::type;
			using ans_type = typename near_base_of<terget, others...>::template check<terget_, new_candidate>::ans_type;
		};
		template<typename terget_>
		struct check<terget_, void, true>{
			using ans_type = typename near_base_of<terget, others...>::template check<terget_, try_type>::ans_type;
		};
		using type = typename check<terget, void>::ans_type;
	};

	template <typename T>
	struct has_begin_and_end {
	private:
		template <class U>
		static auto check(U&& x)->decltype(x.begin(), x.end(), std::true_type{});
		static auto check(...)->std::false_type;
	public:
		using type = decltype(check(std::declval<typename std::decay<T>::type>()));
		constexpr static bool value = type::value;
	};

	template<typename T>
	struct is_iterator{
	private:
		template<typename U>
		static auto check(U&&)->decltype(typename std::iterator_traits<U>::iterator_category{}, std::true_type{});
		static auto check(...)->std::false_type;
	public:
		using type = decltype(check(std::declval<typename std::decay<T>::type>()));
		constexpr static bool value = type::value;
	};

	template<typename T, bool is_iterator_ = is_iterator<T>::value>
	struct is_const_iterator: public std::false_type {};

	template<typename T>
	struct is_const_iterator<T, true> {
	public:
		using type = std::integral_constant<bool, std::is_assignable<decltype(*std::declval<T>()), typename std::iterator_traits<T>::value_type>::value>;
		constexpr static bool value = type::value;
	};

	namespace detail {
		struct result_of_impl {
			template < class Result, class ... Args >
			static Result Func(Result(*)(Args ...));
			template < class T, class Result, class ... Args >
			static Result Func(Result(T::*)(Args ...));
			template < class T, class Result, class ... Args >
			static Result Func(Result(T::*)(Args ...) const);
			template < class T, class FuncType = decltype(&T::operator()) >
			static decltype(Func(std::declval<FuncType>())) Func(T*);
		};
	}
	template < typename Fn >
	struct result_of {
		using type = decltype(detail::result_of_impl::Func(std::declval<std::remove_pointer_t<Fn>*>()));
	};

	template<typename Fn, typename T>
	struct is_applicable {
	private:
		template<typename eFn, typename eT, typename ans_type = decltype(std::declval<eFn>()(std::declval<eT>()))>
		static auto check(eFn&&, eT&&)->std::true_type;
		static auto check(...)->std::false_type;
	public:
		using type = decltype(check(std::declval<Fn>(), std::declval<T>()));
		static constexpr const bool value = type::value;
	};
}
#
#endif
<commit_msg>Add generalized container detector, is_range.<commit_after>#ifndef HMLIB_TYPETRAITS_INC
#define HMLIB_TYPETRAITS_INC 100
#
#include<type_traits>
#include<iterator>
namespace hmLib{
	template<typename type1, typename type2>
	struct select_derived{
		template<typename type, bool Type1IsBase = std::is_base_of<type1,type2>::value, bool Type2IsBase = std::is_base_of<type2, type1>::value>
		struct check{
			using ans_type = void;
		};
		template<typename type>
		struct check<type, true, false>{
			using ans_type = type2;
		};
		template<typename type>
		struct check<type, false, true>{
			using ans_type = type1;
		};
		using type = typename check<void>::ans_type;
	};
	template<typename terget, typename... others>
	struct near_base_of{
		template<typename terget_, typename candidate_>
		struct check{
			using ans_type = candidate_;
		};
		using type = typename check<terget, void>::ans_type;
	};
	template<typename terget, typename try_type, typename... others>
	struct near_base_of<terget, try_type, others...>{
		template<typename terget_, typename candidate_, bool IsBase = std::is_base_of<try_type, terget>::value>
		struct check{
			using ans_type = typename near_base_of<terget, others...>::template check<terget_, candidate_>::ans_type;
		};
		template<typename terget_, typename candidate_>
		struct check<terget_, candidate_, true>{
			using new_candidate = typename select_derived<candidate_, try_type>::type;
			using ans_type = typename near_base_of<terget, others...>::template check<terget_, new_candidate>::ans_type;
		};
		template<typename terget_>
		struct check<terget_, void, true>{
			using ans_type = typename near_base_of<terget, others...>::template check<terget_, try_type>::ans_type;
		};
		using type = typename check<terget, void>::ans_type;
	};

	template <typename T>
	struct has_begin_and_end {
	private:
		template <class U>
		static auto check(U&& x)->decltype(x.begin(), x.end(), std::true_type{});
		static auto check(...)->std::false_type;
	public:
		[[deprecated("please use is_range<T> for detecting the range-like classes.")]] typedef decltype(check(std::declval<typename std::decay<T>::type>())) type;
		[[deprecated("please use is_range<T> for detecting the range-like classes.")]] constexpr static bool value = type::value;
	};

	template <typename T>
	struct is_range {
	private:
		template <class U>
		static auto check(U&& x)->decltype(std::begin(x), std::end(x), std::true_type{});
		static auto check(...)->std::false_type;
	public:
		using type = decltype(check(std::declval<typename std::decay<T>::type>()));
		constexpr static bool value = type::value;
	};

	template<typename T>
	struct is_iterator{
	private:
		template<typename U>
		static auto check(U&&)->decltype(typename std::iterator_traits<U>::iterator_category{}, std::true_type{});
		static auto check(...)->std::false_type;
	public:
		using type = decltype(check(std::declval<typename std::decay<T>::type>()));
		constexpr static bool value = type::value;
	};

	template<typename T, bool is_iterator_ = is_iterator<T>::value>
	struct is_const_iterator: public std::false_type {};

	template<typename T>
	struct is_const_iterator<T, true> {
	public:
		using type = std::integral_constant<bool, std::is_assignable<decltype(*std::declval<T>()), typename std::iterator_traits<T>::value_type>::value>;
		constexpr static bool value = type::value;
	};

	namespace detail {
		struct result_of_impl {
			template < class Result, class ... Args >
			static Result Func(Result(*)(Args ...));
			template < class T, class Result, class ... Args >
			static Result Func(Result(T::*)(Args ...));
			template < class T, class Result, class ... Args >
			static Result Func(Result(T::*)(Args ...) const);
			template < class T, class FuncType = decltype(&T::operator()) >
			static decltype(Func(std::declval<FuncType>())) Func(T*);
		};
	}
	template < typename Fn >
	struct result_of {
		using type = decltype(detail::result_of_impl::Func(std::declval<std::remove_pointer_t<Fn>*>()));
	};

	template<typename Fn, typename T>
	struct is_applicable {
	private:
		template<typename eFn, typename eT, typename ans_type = decltype(std::declval<eFn>()(std::declval<eT>()))>
		static auto check(eFn&&, eT&&)->std::true_type;
		static auto check(...)->std::false_type;
	public:
		using type = decltype(check(std::declval<Fn>(), std::declval<T>()));
		static constexpr const bool value = type::value;
	};
}
#
#endif
<|endoftext|>


<commit_before>#pragma once

namespace cdp
{
	template <typename T>
	constexpr auto is_complete_impl(int = 0) -> decltype(!sizeof(T))
	{
		return true;
	}

	template <typename T>
	constexpr bool is_complete_impl(...)
	{
		return false;
	}

	template <typename T>
	constexpr bool is_complete()
	{
		return is_complete_impl<T>(0);
	}
}
<commit_msg>Rename helpers to stop code completion from suggesting them<commit_after>#pragma once

namespace cdp
{
	template <typename T>
	constexpr auto _is_complete(int = 0) -> decltype(!sizeof(T))
	{
		return true;
	}

	template <typename T>
	constexpr bool _is_complete(...)
	{
		return false;
	}

	template <typename T>
	constexpr bool is_complete()
	{
		return _is_complete<T>(0);
	}
}
<|endoftext|>


<commit_before>#include "Morton_shuffler.hpp"
#include <iostream>

extern int myrank, nprocs;

Morton_shuffler::Morton_shuffler(
        int N0, int N1, int N2,
        int d,
        int nfiles)
{
    this->d = d;
    if (nprocs % nfiles != 0)
    {
        std::cerr <<
            "Number of output files incompatible with number of processes.\n"
            "Aborting.\n" << std::endl;
        exit(EXIT_FAILURE);
    }
    int n[4];

    // various descriptions for the real data
    n[0] = N0;
    n[1] = N1;
    n[2] = N2;
    n[3] = d;
    this->dinput = new field_descriptor(4, n, MPI_REAL4, MPI_COMM_WORLD);
    n[0] = N0/8;
    n[1] = N1/8;
    n[2] = N2/8;
    n[3] = 8*8*8*this->d;
    this->drcubbie = new field_descriptor(4, n, MPI_REAL4, MPI_COMM_WORLD);
    n[0] = (N0/8) * (N1/8) * (N2/8);
    n[1] = 8*8*8*this->d;
    this->dzcubbie = new field_descriptor(2, n, MPI_REAL4, MPI_COMM_WORLD);

    //set up output file descriptor
    int out_rank, out_nprocs;
    out_nprocs = nprocs/nfiles;
    this->out_group = myrank / out_nprocs;
    out_rank = myrank % out_nprocs;
    n[0] = ((N0/8) * (N1/8) * (N2/8)) / nfiles;
    n[1] = 8*8*8*this->d;
    MPI_Comm_split(MPI_COMM_WORLD, this->out_group, out_rank, &this->out_communicator);
    this->doutput = new field_descriptor(2, n, MPI_REAL4, this->out_communicator);
}

Morton_shuffler::~Morton_shuffler()
{
    delete this->dinput;
    delete this->drcubbie;
    delete this->dzcubbie;
    delete this->doutput;

    MPI_Comm_free(&this->out_communicator);
}

int Morton_shuffler::shuffle(
        float *a,
        const char *base_fname)
{
    // array where shuffled data will be placed
    float *rtmp = fftwf_alloc_real(this->drcubbie->local_size);

    // shuffle into z order
    ptrdiff_t z, zz;
    int rid, zid;
    int kk;
    ptrdiff_t cubbie_size = 8*8*8*this->d;
    ptrdiff_t cc;
    float *rz = fftwf_alloc_real(cubbie_size);
    for (int k = 0; k < this->drcubbie->sizes[0]; k++)
    {
        rid = this->drcubbie->rank(k);
        kk = k - this->drcubbie->starts[0];
        for (int j = 0; j < this->drcubbie->sizes[1]; j++)
        for (int i = 0; i < this->drcubbie->sizes[2]; i++)
        {
            z = regular_to_zindex(k, j, i);
            zid = this->dzcubbie->rank(z);
            zz = z - this->dzcubbie->starts[0];
            if (myrank == rid || myrank == zid)
            {
                // first, copy data into cubbie
                if (myrank == rid)
                    for (int tk = 0; tk < 8; tk++)
                    for (int tj = 0; tj < 8; tj++)
                    {
                        cc = (((kk*8+tk)*this->dinput->sizes[1] + (j*8+tj)) *
                              this->dinput->sizes[2] + i*8)*this->d;
                        std::copy(
                                a + cc,
                                a + cc + 8*this->d,
                                rz + (tk*8 + tj)*8*this->d);
                    }
                // now copy or send/receive to zindexed array
                if (rid == zid) std::copy(
                        rz,
                        rz + cubbie_size,
                        rtmp + zz*cubbie_size);
                else
                {
                    if (myrank == rid) MPI_Send(
                            rz,
                            cubbie_size,
                            MPI_REAL4,
                            zid,
                            z,
                            MPI_COMM_WORLD);
                    else MPI_Recv(
                            rtmp + zz*cubbie_size,
                            cubbie_size,
                            MPI_REAL4,
                            rid,
                            z,
                            MPI_COMM_WORLD,
                            MPI_STATUS_IGNORE);
                }
            }
        }
    }
    fftwf_free(rz);

    char temp_char[200];
    sprintf(temp_char,
            "%s_z%.7x",
            base_fname,
            this->out_group*this->doutput->sizes[0]);
    this->doutput->write(temp_char, rtmp);
    fftwf_free(rtmp);
    return EXIT_SUCCESS;
}

<commit_msg>fix (?) file write<commit_after>#include "Morton_shuffler.hpp"
#include <iostream>

extern int myrank, nprocs;

Morton_shuffler::Morton_shuffler(
        int N0, int N1, int N2,
        int d,
        int nfiles)
{
    this->d = d;
    if (nprocs % nfiles != 0)
    {
        std::cerr <<
            "Number of output files incompatible with number of processes.\n"
            "Aborting.\n" << std::endl;
        exit(EXIT_FAILURE);
    }
    int n[4];

    // various descriptions for the real data
    n[0] = N0;
    n[1] = N1;
    n[2] = N2;
    n[3] = this->d;
    this->dinput = new field_descriptor(4, n, MPI_REAL4, MPI_COMM_WORLD);
    n[0] = N0/8;
    n[1] = N1/8;
    n[2] = N2/8;
    n[3] = 8*8*8*this->d;
    this->drcubbie = new field_descriptor(4, n, MPI_REAL4, MPI_COMM_WORLD);
    n[0] = (N0/8) * (N1/8) * (N2/8);
    n[1] = 8*8*8*this->d;
    this->dzcubbie = new field_descriptor(2, n, MPI_REAL4, MPI_COMM_WORLD);

    //set up output file descriptor
    int out_rank, out_nprocs;
    out_nprocs = nprocs/nfiles;
    this->out_group = myrank / out_nprocs;
    out_rank = myrank % out_nprocs;
    n[0] = ((N0/8) * (N1/8) * (N2/8)) / nfiles;
    n[1] = 8*8*8*this->d;
    MPI_Comm_split(MPI_COMM_WORLD, this->out_group, out_rank, &this->out_communicator);
    this->doutput = new field_descriptor(2, n, MPI_REAL4, this->out_communicator);
}

Morton_shuffler::~Morton_shuffler()
{
    delete this->dinput;
    delete this->drcubbie;
    delete this->dzcubbie;
    delete this->doutput;

    MPI_Comm_free(&this->out_communicator);
}

int Morton_shuffler::shuffle(
        float *a,
        const char *base_fname)
{
    // array where shuffled data will be placed
    float *rtmp = fftwf_alloc_real(this->drcubbie->local_size);

    // shuffle into z order
    ptrdiff_t z, zz;
    int rid, zid;
    int kk;
    ptrdiff_t cubbie_size = 8*8*8*this->d;
    ptrdiff_t cc;
    float *rz = fftwf_alloc_real(cubbie_size);
    for (int k = 0; k < this->drcubbie->sizes[0]; k++)
    {
        rid = this->drcubbie->rank(k);
        kk = k - this->drcubbie->starts[0];
        for (int j = 0; j < this->drcubbie->sizes[1]; j++)
        for (int i = 0; i < this->drcubbie->sizes[2]; i++)
        {
            z = regular_to_zindex(k, j, i);
            zid = this->dzcubbie->rank(z);
            zz = z - this->dzcubbie->starts[0];
            if (myrank == rid || myrank == zid)
            {
                // first, copy data into cubbie
                if (myrank == rid)
                    for (int tk = 0; tk < 8; tk++)
                    for (int tj = 0; tj < 8; tj++)
                    {
                        cc = (((kk*8+tk)*this->dinput->sizes[1] + (j*8+tj)) *
                              this->dinput->sizes[2] + i*8)*this->d;
                        std::copy(
                                a + cc,
                                a + cc + 8*this->d,
                                rz + (tk*8 + tj)*8*this->d);
                    }
                // now copy or send/receive to zindexed array
                if (rid == zid) std::copy(
                        rz,
                        rz + cubbie_size,
                        rtmp + zz*cubbie_size);
                else
                {
                    if (myrank == rid) MPI_Send(
                            rz,
                            cubbie_size,
                            MPI_REAL4,
                            zid,
                            z,
                            MPI_COMM_WORLD);
                    else MPI_Recv(
                            rtmp + zz*cubbie_size,
                            cubbie_size,
                            MPI_REAL4,
                            rid,
                            z,
                            MPI_COMM_WORLD,
                            MPI_STATUS_IGNORE);
                }
            }
        }
    }
    fftwf_free(rz);

    char temp_char[200];
    sprintf(temp_char,
            "%s_z%.7x",
            base_fname,
            this->out_group*this->doutput->sizes[0]);
    this->doutput->write(temp_char, rtmp);
    //this->doutput->write(temp_char, rtmp + this->out_group*this->doutput->sizes[0]);
    fftwf_free(rtmp);
    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>class Solution {

    bool *rows;
    bool *cols;
    bool *add;
    bool *diff;
    int n;

    bool valid(int i, int j)
    {
        if(!rows[i] && !cols[j] && !add[i+j] && !diff[i-j+n])
            return true;
        return false;
    }

    void help(vector<vector<string>> &result, vector<pair<int, int>> &tmp, int i)
    {
        if(i == n)
        {
            if(n == tmp.size())
            {
                string s(n, '.');
                vector<string>t{n,s};
                for(int k = 0;k < tmp.size();k++)
                    t[tmp[k].first][tmp[k].second] = 'Q';
                result.push_back(t);
            }
        } else {
            for(int j = 0;j < n;j++)
            {
                if(valid(i, j))
                {
                    rows[i] = cols[j] = add[i+j] = diff[i-j+n] = true;
                    tmp.push_back(make_pair(i, j));
                    help(result, tmp, i+1);
                    tmp.pop_back();
                    rows[i] = cols[j] = add[i+j] = diff[i-j+n] = false;
                }
            }
        }
    }

public:
    vector<vector<string> > solveNQueens(int n) {

        rows = new bool[n];
        cols = new bool[n];
        add = new bool[2*n];
        diff = new bool[2*n];
        this->n = n;

        vector<vector<string>> result;
        vector<pair<int, int>> tmp;

        help(result, tmp, 0);

        return result;
    }
};<commit_msg>N-Queens<commit_after>class Solution {

    bool *rows;
    bool *cols;
    bool *add;
    bool *diff;
    int n;

    bool valid(int i, int j)
    {
        if(!rows[i] && !cols[j] && !add[i+j] && !diff[i-j+n])
            return true;
        return false;
    }

    void help(vector<vector<string>> &result, vector<pair<int, int>> &tmp, int i)
    {
        if(i == n)
        {
            string s(n, '.');
            vector<string>t{n,s};
            for(int k = 0;k < tmp.size();k++)
                t[tmp[k].first][tmp[k].second] = 'Q';
            result.push_back(t);
            return;
        }

        for(int j = 0;j < n;j++)
        {
            if(valid(i, j))
            {
                rows[i] = cols[j] = add[i+j] = diff[i-j+n] = true;
                tmp.push_back(make_pair(i, j));
                help(result, tmp, i+1);
                tmp.pop_back();
                rows[i] = cols[j] = add[i+j] = diff[i-j+n] = false;
            }
        }
    }

public:
    vector<vector<string> > solveNQueens(int n) {

        rows = new bool[n];
        cols = new bool[n];
        add = new bool[2*n];
        diff = new bool[2*n];
        this->n = n;

        vector<vector<string>> result;
        vector<pair<int, int>> tmp;

        help(result, tmp, 0);

        return result;
    }

};<|endoftext|>


<commit_before>#pragma once

#include <type_traits>
#include <utility>

namespace yks {

template <typename T>
class Optional {
public:
	Optional()
		: present(false)
	{
		update_debug_ptr();
	}

	Optional(const Optional& o) {
		if (o.present) {
			new (&storage) T(*o.get_pointer());
		}
		present = o.present;
		update_debug_ptr();
	}

	Optional(Optional&& o) {
		if (o.present) {
			new (&storage) T(std::move(*o.get_pointer()));
		}
		present = o.present;
		update_debug_ptr();
	}

	~Optional() {
		if (present) {
			get_pointer()->~T();
		}
	}

	Optional& operator=(const Optional& o) {
		if (present) {
			if (o.present) {
				*get_pointer() = *o.get_pointer();
			} else {
				get_pointer()->~T();
			}
		} else {
			if (o.present) {
				new (get_pointer()) T(o);
			}
		}
		present = o.present;
		update_debug_ptr();
	}

	template <typename... Args>
	void emplace(Args&&... args)
	{
		if (present) {
			get_pointer()->~T();
		}
		new (&storage) T(std::forward<Args>(args)...);
		present = true;
		update_debug_ptr();
	}

	explicit operator bool() const { return present; }

	const T& operator* () const { return *get_pointer(); }
	      T& operator* ()       { return *get_pointer(); }
	const T* operator->() const { return  get_pointer(); }
	      T* operator->()       { return  get_pointer(); }

	template <typename U>
	T value_or(U&& value) const {
		return present ? *get_pointer() : std::move(value);
	}

private:
	typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type storage;
	bool present;
#if _DEBUG
	const T* debug_ptr;
#endif

	void update_debug_ptr() {
#if _DEBUG
		debug_ptr = present ? static_cast<const T*>(static_cast<const void*>(&storage)) : nullptr;
#endif
	}

	const T* get_pointer() const {
		assert(present);
		return static_cast<const T*>(static_cast<const void*>(&storage));
	}

	T* get_pointer() {
		assert(present);
		return static_cast<T*>(static_cast<void*>(&storage));
	}
};

template <typename T, typename... Args>
Optional<T> make_optional(Args&&... args) {
	Optional<T> optional;
	optional.emplace(std::forward<Args>(args)...);
	return optional;
}

}
<commit_msg>Fixed broken operator= in Optional<commit_after>#pragma once

#include <type_traits>
#include <utility>

namespace yks {

template <typename T>
class Optional {
public:
	Optional()
		: present(false)
	{
		update_debug_ptr();
	}

	Optional(const Optional& o) {
		if (o.present) {
			new (&storage) T(*o.get_pointer());
		}
		present = o.present;
		update_debug_ptr();
	}

	Optional(Optional&& o) {
		if (o.present) {
			new (&storage) T(std::move(*o.get_pointer()));
		}
		present = o.present;
		update_debug_ptr();
	}

	~Optional() {
		if (present) {
			get_pointer()->~T();
		}
	}

	Optional& operator=(const Optional& o) {
		if (present) {
			if (o.present) {
				*get_pointer() = *o.get_pointer();
			} else {
				get_pointer()->~T();
			}
		} else {
			if (o.present) {
				new (&storage) T(*o.get_pointer());
			}
		}
		present = o.present;
		update_debug_ptr();

		return *this;
	}

	template <typename... Args>
	void emplace(Args&&... args)
	{
		if (present) {
			get_pointer()->~T();
		}
		new (&storage) T(std::forward<Args>(args)...);
		present = true;
		update_debug_ptr();
	}

	explicit operator bool() const { return present; }

	const T& operator* () const { return *get_pointer(); }
	      T& operator* ()       { return *get_pointer(); }
	const T* operator->() const { return  get_pointer(); }
	      T* operator->()       { return  get_pointer(); }

	template <typename U>
	T value_or(U&& value) const {
		return present ? *get_pointer() : std::move(value);
	}

private:
	typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type storage;
	bool present;
#if _DEBUG
	const T* debug_ptr;
#endif

	void update_debug_ptr() {
#if _DEBUG
		debug_ptr = present ? static_cast<const T*>(static_cast<const void*>(&storage)) : nullptr;
#endif
	}

	const T* get_pointer() const {
		assert(present);
		return static_cast<const T*>(static_cast<const void*>(&storage));
	}

	T* get_pointer() {
		assert(present);
		return static_cast<T*>(static_cast<void*>(&storage));
	}
};

template <typename T, typename... Args>
Optional<T> make_optional(Args&&... args) {
	Optional<T> optional;
	optional.emplace(std::forward<Args>(args)...);
	return optional;
}

}
<|endoftext|>


<commit_before>#include "PanelComponents.h"
//#include "timeKeeper.h"
#include "Arduino.h"

//---Switch------------------------------------------------------
PanelSwitch::PanelSwitch( void )
{

}

void PanelSwitch::init( uint8_t pinNum )
{
	pinNumber = pinNum;
	pinMode( pinNumber, INPUT_PULLUP );
	update();
	//force newData high in case knob starts on last value
	newData = 1;
}

void PanelSwitch::update( void )
{
	uint8_t tempState = digitalRead( pinNumber ) ^ 0x01;
	if( state != tempState )
	{
		state = tempState;
		newData = 1;
	}
}

uint8_t PanelSwitch::getState( void )
{
	newData = 0;

	return state;
}

//---Button------------------------------------------------------
PanelButton::PanelButton( void )
{
	beingHeld = 0;
	bank = 0;
}

void PanelButton::init( uint8_t pinInput )
{
	init( pinInput, 0 );
}

void PanelButton::init( uint8_t pinInput, uint8_t bankInput )
{
	bank = bankInput;
	pinNumber = pinInput;
	if( bank == 0 )
	{
		pinMode( pinNumber, INPUT_PULLUP );
		update();
		//force newData high in case knob starts on last value
		newData = 1;
	}
	else
	{
		//Do bank related initialization here
	}
}

//This is the intended operation:
// Button is pressed. If it has been long enough since last movement:
//   update newData
//   clear timer
// If This has already been done, check for button held.  If so,
//   update newData
//   clear timer
void PanelButton::update( void )
{
	uint8_t tempState;
	if( bank == 0 )
	{
		tempState = digitalRead( pinNumber ) ^ 0x01;
	}
	else
	{
		tempState = cache ^ 0x01;  //Take externally provided data
	}

	switch( state )
	{
	case 0: //Last state was 0
	case 1: //Last state was 1
		if(( state != tempState ) && (buttonDebounceTimeKeeper.mGet() > 50))
		{
			//  Serial.println(buttonDebounceTimeKeeper.mGet());
			state = tempState;
			newData = 1;
			//Start the timer
			buttonDebounceTimeKeeper.mClear();
			if( tempState == 1 )
			{
				//Ok, we are being held down
				beingHeld = 1;
			}
		}
		if(( tempState == 1 )&&( beingHeld == 1 ))
		{
			//We're being held
			if(buttonDebounceTimeKeeper.mGet() > 1000)
			{
				newData = 1;
				state = 2;//BUTTONHOLD;
				//Serial.println("Got it.");
			}
			else
			{
				//Serial.println("WAITING!!!");
			}
		}
		break;
	case 2: //In the process of holding
		if(( tempState == 0) && ( state != tempState ) && (buttonDebounceTimeKeeper.mGet() > 50))
		{
			//  Serial.println(buttonDebounceTimeKeeper.mGet());
			state = tempState;
			newData = 1;
			//Start the timer
			buttonDebounceTimeKeeper.mClear();
			beingHeld = 0;
		}
		break;
	default:
		break;
	}

}

uint8_t PanelButton::getState( void )
{
	newData = 0;

	return state;
}

void PanelButton::setBank( uint8_t newBank )
{
	bank = newBank;

}

//---Led---------------------------------------------------------
PanelLed::PanelLed( void )
{
	state = LEDOFF;
	bank = 0;
}

void PanelLed::init( uint8_t pinInput )
{
	init( pinInput, 0 );
}

void PanelLed::init( uint8_t pinInput, uint8_t bankInput )
{
	bank = bankInput;
	pinNumber = pinInput;
	if( bank == 0 )
	{
		pinMode( pinNumber, OUTPUT );
		update();
	}
	else
	{
		//Do bank related initialization here
	}

}

void PanelLed::init( uint8_t pinInput, uint8_t bankInput, volatile uint8_t * volatile flasherAddress, volatile uint8_t * volatile fastFlasherAddress )
{
	init( pinInput, bankInput ); //Do regular init, plus:

	flasherState = flasherAddress;
	fastFlasherState = fastFlasherAddress;

}

void PanelLed::update( void )
{
	uint8_t outputValue = 0;
	switch(state)
	{
	case LEDON:
		outputValue = 0;
		break;
	case LEDFLASHING:
		outputValue = *flasherState;
		break;
	case LEDFLASHINGFAST:
		outputValue = *fastFlasherState;
		break;
	default:
	case LEDOFF:
		outputValue = 1;
		break;
	}

	Serial.print("A:");
	Serial.print(*flasherState);
	if( bank == 0 )
	{
		digitalWrite( pinNumber, outputValue );
		Serial.print("B:");
		Serial.print(*flasherState);
	}
	if( bank != 0 )
	{
		Serial.print("C:");
		Serial.print(*flasherState);
		cache = outputValue & 0x0001;
	}

}

ledState_t PanelLed::getState( void )
{
	return state;

}

void PanelLed::setState( ledState_t inputValue )
{
	state = inputValue;

}

void PanelLed::setBank( uint8_t inputBank )
{
	bank = inputBank;

}

//---Selector----------------------------------------------------
PanelSelector::PanelSelector( void )
{

}

// 8 bit resolution on the ADC should be fine.  Right shift on analogRead
void PanelSelector::init( uint8_t pinNum, uint8_t maxInput, uint8_t minInput )
{
	pinNumber = pinNum;
	pinMode( pinNumber, INPUT );
	//Set up the ranges
	uint8_t stepHeight = ( maxInput - minInput ) / 9;
	thresholds[0] = minInput + ( stepHeight / 2 );
	int i;
	for( i = 1; i < 9; i++ )
	{
		thresholds[i] = thresholds[i - 1] + stepHeight;
	}
	update();
	//force newData high in case knob starts on last value
	newData = 1;
}

void PanelSelector::update( void )
{
	uint8_t analogReadRaw = (analogRead( pinNumber )) >> 2;  //Now 8 bits
	uint8_t tempState = 0;
	//Seek the position
	int i;
	for( i = 0; i < 9; i++ )
	{
		if( analogReadRaw > thresholds[i] )
		{
			tempState = i + 1; //It's this or higher
		}
	}
	//Check if new
	if( state != tempState )
	{
		state = tempState;
		newData = 1;
	}
}

uint8_t PanelSelector::getState( void )
{
	newData = 0;

	return state;
}<commit_msg>removed print statements<commit_after>#include "PanelComponents.h"
//#include "timeKeeper.h"
#include "Arduino.h"

//---Switch------------------------------------------------------
PanelSwitch::PanelSwitch( void )
{

}

void PanelSwitch::init( uint8_t pinNum )
{
	pinNumber = pinNum;
	pinMode( pinNumber, INPUT_PULLUP );
	update();
	//force newData high in case knob starts on last value
	newData = 1;
}

void PanelSwitch::update( void )
{
	uint8_t tempState = digitalRead( pinNumber ) ^ 0x01;
	if( state != tempState )
	{
		state = tempState;
		newData = 1;
	}
}

uint8_t PanelSwitch::getState( void )
{
	newData = 0;

	return state;
}

//---Button------------------------------------------------------
PanelButton::PanelButton( void )
{
	beingHeld = 0;
	bank = 0;
}

void PanelButton::init( uint8_t pinInput )
{
	init( pinInput, 0 );
}

void PanelButton::init( uint8_t pinInput, uint8_t bankInput )
{
	bank = bankInput;
	pinNumber = pinInput;
	if( bank == 0 )
	{
		pinMode( pinNumber, INPUT_PULLUP );
		update();
		//force newData high in case knob starts on last value
		newData = 1;
	}
	else
	{
		//Do bank related initialization here
	}
}

//This is the intended operation:
// Button is pressed. If it has been long enough since last movement:
//   update newData
//   clear timer
// If This has already been done, check for button held.  If so,
//   update newData
//   clear timer
void PanelButton::update( void )
{
	uint8_t tempState;
	if( bank == 0 )
	{
		tempState = digitalRead( pinNumber ) ^ 0x01;
	}
	else
	{
		tempState = cache ^ 0x01;  //Take externally provided data
	}

	switch( state )
	{
	case 0: //Last state was 0
	case 1: //Last state was 1
		if(( state != tempState ) && (buttonDebounceTimeKeeper.mGet() > 50))
		{
			//  Serial.println(buttonDebounceTimeKeeper.mGet());
			state = tempState;
			newData = 1;
			//Start the timer
			buttonDebounceTimeKeeper.mClear();
			if( tempState == 1 )
			{
				//Ok, we are being held down
				beingHeld = 1;
			}
		}
		if(( tempState == 1 )&&( beingHeld == 1 ))
		{
			//We're being held
			if(buttonDebounceTimeKeeper.mGet() > 1000)
			{
				newData = 1;
				state = 2;//BUTTONHOLD;
				//Serial.println("Got it.");
			}
			else
			{
				//Serial.println("WAITING!!!");
			}
		}
		break;
	case 2: //In the process of holding
		if(( tempState == 0) && ( state != tempState ) && (buttonDebounceTimeKeeper.mGet() > 50))
		{
			//  Serial.println(buttonDebounceTimeKeeper.mGet());
			state = tempState;
			newData = 1;
			//Start the timer
			buttonDebounceTimeKeeper.mClear();
			beingHeld = 0;
		}
		break;
	default:
		break;
	}

}

uint8_t PanelButton::getState( void )
{
	newData = 0;

	return state;
}

void PanelButton::setBank( uint8_t newBank )
{
	bank = newBank;

}

//---Led---------------------------------------------------------
PanelLed::PanelLed( void )
{
	state = LEDOFF;
	bank = 0;
}

void PanelLed::init( uint8_t pinInput )
{
	init( pinInput, 0 );
}

void PanelLed::init( uint8_t pinInput, uint8_t bankInput )
{
	bank = bankInput;
	pinNumber = pinInput;
	if( bank == 0 )
	{
		pinMode( pinNumber, OUTPUT );
		update();
	}
	else
	{
		//Do bank related initialization here
	}

}

void PanelLed::init( uint8_t pinInput, uint8_t bankInput, volatile uint8_t * volatile flasherAddress, volatile uint8_t * volatile fastFlasherAddress )
{
	init( pinInput, bankInput ); //Do regular init, plus:

	flasherState = flasherAddress;
	fastFlasherState = fastFlasherAddress;

}

void PanelLed::update( void )
{
	uint8_t outputValue = 0;
	switch(state)
	{
	case LEDON:
		outputValue = 0;
		break;
	case LEDFLASHING:
		outputValue = *flasherState;
		break;
	case LEDFLASHINGFAST:
		outputValue = *fastFlasherState;
		break;
	default:
	case LEDOFF:
		outputValue = 1;
		break;
	}

	//Serial.print("A:");
	//Serial.print(*flasherState);
	if( bank == 0 )
	{
		digitalWrite( pinNumber, outputValue );
		//Serial.print("B:");
		//Serial.print(*flasherState);
	}
	if( bank != 0 )
	{
		//Serial.print("C:");
		//Serial.print(*flasherState);
		cache = outputValue & 0x0001;
	}

}

ledState_t PanelLed::getState( void )
{
	return state;

}

void PanelLed::setState( ledState_t inputValue )
{
	state = inputValue;

}

void PanelLed::setBank( uint8_t inputBank )
{
	bank = inputBank;

}

//---Selector----------------------------------------------------
PanelSelector::PanelSelector( void )
{

}

// 8 bit resolution on the ADC should be fine.  Right shift on analogRead
void PanelSelector::init( uint8_t pinNum, uint8_t maxInput, uint8_t minInput )
{
	pinNumber = pinNum;
	pinMode( pinNumber, INPUT );
	//Set up the ranges
	uint8_t stepHeight = ( maxInput - minInput ) / 9;
	thresholds[0] = minInput + ( stepHeight / 2 );
	int i;
	for( i = 1; i < 9; i++ )
	{
		thresholds[i] = thresholds[i - 1] + stepHeight;
	}
	update();
	//force newData high in case knob starts on last value
	newData = 1;
}

void PanelSelector::update( void )
{
	uint8_t analogReadRaw = (analogRead( pinNumber )) >> 2;  //Now 8 bits
	uint8_t tempState = 0;
	//Seek the position
	int i;
	for( i = 0; i < 9; i++ )
	{
		if( analogReadRaw > thresholds[i] )
		{
			tempState = i + 1; //It's this or higher
		}
	}
	//Check if new
	if( state != tempState )
	{
		state = tempState;
		newData = 1;
	}
}

uint8_t PanelSelector::getState( void )
{
	newData = 0;

	return state;
}<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <cstring>
#include <cassert>
#include <opencv2/core/core.hpp>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Lepton_Frame.h"
#include "Lepton_Driver.h"
#include "OpenCV_Adapter.h"
#include "Person_Finder.h"

int socket_fd;
struct sockaddr_in servaddr;

static void setupConnection(char *hostname)
{
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(11539);
    servaddr.sin_addr.s_addr = inet_addr(hostname);
    connect(socket_fd, (const sockaddr*)&servaddr, sizeof(servaddr));
}

int main(int argc, char **argv)
{
	if (argc < 2) {
		return -1;
	}

	setupConnection(argv[1]);

	setupSPI();

	for (;;) {
        uint8_t *frame = nextFrame();
        if (!checkFrame()) {
            continue;
        }
        cv::Mat img = convertData(frame);
        // cv::Mat processed = img.clone();
        cv::Mat processed = findPerson(img);
        // cv::Mat processed(SCAN_LINES, SCAN_COLUMNS, CV_8UC3, cv::Scalar(255,0,0));
        // fprintf(stderr, "isContinuous = %d\n", processed.isContinuous());
        write(socket_fd, processed.data, SCAN_LINES * SCAN_COLUMNS * 3);
	}
}
<commit_msg>Update for new Lepton_Data_Sender API.<commit_after>#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <cstring>
#include <cassert>
#include <opencv2/core/core.hpp>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Lepton_Frame.h"
#include "Lepton_Driver.h"
#include "OpenCV_Adapter.h"
#include "Person_Finder.h"

int socket_fd;
struct sockaddr_in servaddr;

static void setupConnection(char *hostname)
{
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(11539);
    servaddr.sin_addr.s_addr = inet_addr(hostname);
    connect(socket_fd, (const sockaddr*)&servaddr, sizeof(servaddr));
}

int main(int argc, char **argv)
{
	if (argc < 2) {
		return -1;
	}

	setupConnection(argv[1]);

	setupLepton();

	for (;;) {
        uint8_t *frame = nextFrame();
        if (!checkFrame()) {
            continue;
        }
        cv::Mat img = convertData(frame);
        // cv::Mat processed = img.clone();
        cv::Mat processed = findPerson(img);
        // cv::Mat processed(SCAN_LINES, SCAN_COLUMNS, CV_8UC3, cv::Scalar(255,0,0));
        // fprintf(stderr, "isContinuous = %d\n", processed.isContinuous());
        write(socket_fd, processed.data, SCAN_LINES * SCAN_COLUMNS * 3);
	}
}
<|endoftext|>


<commit_before>#include <FWPlatform.h>
#include <EventLoop.h>
#include <CurlClient.h>
#include <Logger.h>
#include <ContextCairo.h>
#include <SDLSoundCanvas.h>
#include <Message.h>
#include <FWApplication.h>

#include <TouchEvent.h>
#include <DrawEvent.h>
#include <SysEvent.h>

#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <cstdio>
#include <cstdlib>
#include <sys/time.h>

using namespace std;

class PlatformSDL : public FWPlatform {
public:
  PlatformSDL() : FWPlatform(1.0f,
			     // "#version 300 es",
			     "#version 100",
			     true) { }

  double getTime() const override {
    struct timeval tv;
    struct timezone tz;
    int r = gettimeofday(&tv, &tz);
    double t = 0;
    if (r == 0) {
      t = (double)tv.tv_sec + tv.tv_usec / 1000000.0;
    }
    return t;
  }

  string getLocalFilename(const char * fn, FileType type) {
    string s = "assets/";
    return s + fn;
  }

  std::shared_ptr<HTTPClientFactory> createHTTPClientFactory() const {
    return std::make_shared<CurlClientFactory>();
  }

  int showActionSheet(const FWRect&, const FWActionSheet&) {
    return 0;
  }

  std::shared_ptr<canvas::ContextFactory> createContextFactory() const {
    return std::shared_ptr<canvas::ContextFactory>(new canvas::CairoContextFactory);
  }

  void sendMessage(const Message & message) override {
    cerr << "sendMessage(" << int(message.getType()) << ")\n";
    FWPlatform::sendMessage(message);
    switch (message.getType()) {
    case Message::SET_CAPTION:
      SDL_WM_SetCaption(message.getTextValue().c_str(),
			message.getTextValue().c_str());
      break;
    case Message::SHOW_MESSAGE_DIALOG:
#if 0
      SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_INFORMATION,
				title.c_str(),
				message.c_str(),
				NULL);
#endif
      break;
    default:
      break;
    }
  }

  std::shared_ptr<SoundCanvas> createSoundCanvas() const override {
    return std::make_shared<SDLSoundCanvas>();
  }

  std::shared_ptr<Logger> createLogger() const override {
    return std::make_shared<BasicLogger>();
  }

  // std::shared_ptr<EventLoop> createEventLoop() override;

  std::string showTextEntryDialog(const std::string & message) {
    return "";
  }

  std::string getBundleFilename(const char * filename) {
    string s = "assets/";
    return s + filename;
  }

  void storeValue(const std::string & key, const std::string & value) {

  }

  std::string loadValue(const std::string & key) {
    return "";
  }

  void swapBuffers() {
    SDL_GL_SwapBuffers( );
  }

  void run() {
    SDL_Event event;

    cerr << "starting runloop\n";

    while ( true ) {
      /* Grab all the events off the queue. */
      while( SDL_PollEvent( &event ) ) {
	switch( event.type ) {
	case SDL_KEYDOWN:
	  /* Handle key presses. */
	  // handle_key_down( &event.key.keysym );
	  break;
	case SDL_MOUSEBUTTONDOWN:
	  {
	    TouchEvent ev(TouchEvent::ACTION_DOWN, mouse_x, mouse_y, getTime(), 0);
	    postEvent(getActiveViewId(), ev);
	    button_pressed = true;
	  }
	  break;
	case SDL_MOUSEBUTTONUP:
	  {
	    TouchEvent ev(TouchEvent::ACTION_UP, mouse_x, mouse_y, getTime(), 0);
	    postEvent(getActiveViewId(), ev);
	    button_pressed = false;
	  }
	  break;
	case SDL_MOUSEMOTION:
	  if (button_pressed) {
	    TouchEvent ev(TouchEvent::ACTION_MOVE, event.motion.x, event.motion.y, getTime(), 0);
	    postEvent(getActiveViewId(), ev);
	  }
	  mouse_x = event.motion.x;
	  mouse_y = event.motion.y;
	  break;
	case SDL_VIDEORESIZE:
	  {
	    int w = event.resize.w, h = event.resize.h;
	    cerr << "resized (" << w << " " << h << ")\n";
	    setDisplayWidth(w);
	    setDisplayHeight(h);
	    getApplication().getFirstChild()->onResize(w, h, w, h);
	  }
	  break;
	case SDL_QUIT:
	  return;
	}
      }

      getApplication().loadEvents();

      if (getApplication().getFirstChild()->onUpdate(getTime())) {
	DrawEvent ev;
	postEvent(getActiveViewId(), ev);
	swapBuffers();
      }
    }
  }

private:
  bool button_pressed = false;
  int mouse_x = 0, mouse_y = 0;
};

#if 0
static void handle_key_down(SDL_keysym* keysym) {

    /*
     * We're only interested if 'Esc' has
     * been presssed.
     *
     * EXERCISE:
     * Handle the arrow keys and have that change the
     * viewing position/angle.
     */
    switch( keysym->sym ) {
    case SDLK_ESCAPE:
        quit_tutorial( 0 );
        break;
    case SDLK_SPACE:
        should_rotate = !should_rotate;
        break;
    default:
        break;
    }

}
#endif

extern FWApplication * applicationMain();

int main(int argc, char *argv[]) {
  if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO ) < 0 ) {
    /* Failed, exit. */
    fprintf( stderr, "Video initialization failed: %s\n",
             SDL_GetError( ) );
    SDL_Quit( );
    exit(1);
  }

  const SDL_VideoInfo * info = SDL_GetVideoInfo( );

  if (!info) {
    /* This should probably never happen. */
    fprintf( stderr, "Video query failed: %s\n", SDL_GetError() );
    SDL_Quit();
    exit(1);
  }

  int width = 800, height = 600;
  int bpp = info->vfmt->BitsPerPixel;

  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

  int flags = SDL_OPENGL; // | SDL_FULLSCREEN;

  if (SDL_SetVideoMode( width, height, bpp, flags ) == 0) {
    fprintf( stderr, "Video mode set failed: %s\n",
             SDL_GetError( ) );
    SDL_Quit();
    exit(1);
  }

  FWApplication * application = applicationMain();

  cerr << "starting, app = " << application << "\n";

  PlatformSDL platform;
  platform.setApplication(application);
  platform.getApplication().initialize(&platform);
  platform.getApplication().onCmdLine(argc, argv);

  platform.setDisplayWidth(width);
  platform.setDisplayHeight(height);
  platform.getApplication().initializeContent();

  platform.run();

#if 0
  auto eventloop = platform.createEventLoop();
  eventloop->run();
#endif

  SysEvent ev(SysEvent::SHUTDOWN);
  ev.dispatch(platform.getApplication());
  SDL_Quit();
  return 0;
}
<commit_msg>add UpdateEvent, add timestamp to SysEvent and DrawEvent<commit_after>#include <FWPlatform.h>
#include <EventLoop.h>
#include <CurlClient.h>
#include <Logger.h>
#include <ContextCairo.h>
#include <SDLSoundCanvas.h>
#include <Message.h>
#include <FWApplication.h>

#include <TouchEvent.h>
#include <DrawEvent.h>
#include <SysEvent.h>
#include <UpdateEvent.h>

#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <cstdio>
#include <cstdlib>
#include <sys/time.h>

using namespace std;

class PlatformSDL : public FWPlatform {
public:
  PlatformSDL() : FWPlatform(1.0f,
			     // "#version 300 es",
			     "#version 100",
			     true) { }

  double getTime() const override {
    struct timeval tv;
    struct timezone tz;
    int r = gettimeofday(&tv, &tz);
    double t = 0;
    if (r == 0) {
      t = (double)tv.tv_sec + tv.tv_usec / 1000000.0;
    }
    return t;
  }

  string getLocalFilename(const char * fn, FileType type) {
    string s = "assets/";
    return s + fn;
  }

  std::shared_ptr<HTTPClientFactory> createHTTPClientFactory() const {
    return std::make_shared<CurlClientFactory>();
  }

  int showActionSheet(const FWRect&, const FWActionSheet&) {
    return 0;
  }

  std::shared_ptr<canvas::ContextFactory> createContextFactory() const {
    return std::shared_ptr<canvas::ContextFactory>(new canvas::CairoContextFactory);
  }

  void sendMessage(const Message & message) override {
    cerr << "sendMessage(" << int(message.getType()) << ")\n";
    FWPlatform::sendMessage(message);
    switch (message.getType()) {
    case Message::SET_CAPTION:
      SDL_WM_SetCaption(message.getTextValue().c_str(),
			message.getTextValue().c_str());
      break;
    case Message::SHOW_MESSAGE_DIALOG:
#if 0
      SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_INFORMATION,
				title.c_str(),
				message.c_str(),
				NULL);
#endif
      break;
    default:
      break;
    }
  }

  std::shared_ptr<SoundCanvas> createSoundCanvas() const override {
    return std::make_shared<SDLSoundCanvas>();
  }

  std::shared_ptr<Logger> createLogger() const override {
    return std::make_shared<BasicLogger>();
  }

  // std::shared_ptr<EventLoop> createEventLoop() override;

  std::string showTextEntryDialog(const std::string & message) {
    return "";
  }

  std::string getBundleFilename(const char * filename) {
    string s = "assets/";
    return s + filename;
  }

  void storeValue(const std::string & key, const std::string & value) {

  }

  std::string loadValue(const std::string & key) {
    return "";
  }

  void swapBuffers() {
    SDL_GL_SwapBuffers( );
  }

  void run() {
    SDL_Event event;

    cerr << "starting runloop\n";

    while ( true ) {
      /* Grab all the events off the queue. */
      while( SDL_PollEvent( &event ) ) {
	switch( event.type ) {
	case SDL_KEYDOWN:
	  /* Handle key presses. */
	  // handle_key_down( &event.key.keysym );
	  break;
	case SDL_MOUSEBUTTONDOWN:
	  {
	    TouchEvent ev(TouchEvent::ACTION_DOWN, mouse_x, mouse_y, getTime(), 0);
	    postEvent(getActiveViewId(), ev);
	    button_pressed = true;
	  }
	  break;
	case SDL_MOUSEBUTTONUP:
	  {
	    TouchEvent ev(TouchEvent::ACTION_UP, mouse_x, mouse_y, getTime(), 0);
	    postEvent(getActiveViewId(), ev);
	    button_pressed = false;
	  }
	  break;
	case SDL_MOUSEMOTION:
	  if (button_pressed) {
	    TouchEvent ev(TouchEvent::ACTION_MOVE, event.motion.x, event.motion.y, getTime(), 0);
	    postEvent(getActiveViewId(), ev);
	  }
	  mouse_x = event.motion.x;
	  mouse_y = event.motion.y;
	  break;
	case SDL_VIDEORESIZE:
	  {
	    int w = event.resize.w, h = event.resize.h;
	    cerr << "resized (" << w << " " << h << ")\n";
	    setDisplayWidth(w);
	    setDisplayHeight(h);
	    getApplication().getFirstChild()->onResize(w, h, w, h);
	  }
	  break;
	case SDL_QUIT:
	  return;
	}
      }

      getApplication().loadEvents();

      UpdateEvent ev0(getTime());
      postEvent(getActiveViewId(), ev0);
      if (true) {
	DrawEvent ev(getTime());
	postEvent(getActiveViewId(), ev);
	swapBuffers();
      }
    }
  }

private:
  bool button_pressed = false;
  int mouse_x = 0, mouse_y = 0;
};

#if 0
static void handle_key_down(SDL_keysym* keysym) {

    /*
     * We're only interested if 'Esc' has
     * been presssed.
     *
     * EXERCISE:
     * Handle the arrow keys and have that change the
     * viewing position/angle.
     */
    switch( keysym->sym ) {
    case SDLK_ESCAPE:
        quit_tutorial( 0 );
        break;
    case SDLK_SPACE:
        should_rotate = !should_rotate;
        break;
    default:
        break;
    }

}
#endif

extern FWApplication * applicationMain();

int main(int argc, char *argv[]) {
  if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO ) < 0 ) {
    /* Failed, exit. */
    fprintf( stderr, "Video initialization failed: %s\n",
             SDL_GetError( ) );
    SDL_Quit( );
    exit(1);
  }

  const SDL_VideoInfo * info = SDL_GetVideoInfo( );

  if (!info) {
    /* This should probably never happen. */
    fprintf( stderr, "Video query failed: %s\n", SDL_GetError() );
    SDL_Quit();
    exit(1);
  }

  int width = 800, height = 600;
  int bpp = info->vfmt->BitsPerPixel;

  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

  int flags = SDL_OPENGL; // | SDL_FULLSCREEN;

  if (SDL_SetVideoMode( width, height, bpp, flags ) == 0) {
    fprintf( stderr, "Video mode set failed: %s\n",
             SDL_GetError( ) );
    SDL_Quit();
    exit(1);
  }

  FWApplication * application = applicationMain();

  cerr << "starting, app = " << application << "\n";

  PlatformSDL platform;
  platform.setApplication(application);
  platform.getApplication().initialize(&platform);
  platform.getApplication().onCmdLine(argc, argv);

  platform.setDisplayWidth(width);
  platform.setDisplayHeight(height);
  platform.getApplication().initializeContent();

  platform.run();

#if 0
  auto eventloop = platform.createEventLoop();
  eventloop->run();
#endif

  SysEvent ev(platform.getTime(), SysEvent::SHUTDOWN);
  ev.dispatch(platform.getApplication());
  SDL_Quit();
  return 0;
}
<|endoftext|>


<commit_before>/*
 * BDSup2Sub++ (C) 2012 Adam T.
 * Based on code from BDSup2Sub by Copyright 2009 Volker Oth (0xdeadbeef)
 * and Copyright 2012 Miklos Juhasz (mjuhasz)
 *
 *
 * 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 "suphd.h"
#include "subtitleprocessor.h"
#include "subpicturehd.h"
#include "Tools/filebuffer.h"
#include "Tools/bitstream.h"
#include "Tools/timeutil.h"
#include "bitmap.h"
#include "palette.h"
#include <QImage>

SupHD::SupHD(QString fileName, SubtitleProcessor *subtitleProcessor) :
    supFileName(fileName)
{
    this->subtitleProcessor = subtitleProcessor;
}

SupHD::~SupHD()
{
    if (!fileBuffer.isNull())
    {
        fileBuffer.reset();
    }
}

QImage SupHD::image()
{
    return _bitmap.image(_palette);
}

QImage SupHD::image(Bitmap &bitmap)
{
    return bitmap.image(_palette);
}

void SupHD::decode(int index)
{
    if (index < subPictures.size())
    {
        decode(subPictures[index]);
    }
    else
    {
        throw QString("Index: %1 out of bounds.\n").arg(QString::number(index));
    }
}

int SupHD::numFrames()
{
    return subPictures.size();
}

qint64 SupHD::endTime(int index)
{
    return subPictures[index].endTime();
}

qint64 SupHD::startTime(int index)
{
    return subPictures[index].startTime();
}

qint64 SupHD::startOffset(int index)
{
    return subPictures[index].imageBufferOffsetEven();
}

SubPicture *SupHD::subPicture(int index)
{
    return &subPictures[index];
}

void SupHD::readAllSupFrames()
{
    fileBuffer.reset(new FileBuffer(supFileName));

    int index = 0;
    int bufsize = (int)fileBuffer->getSize();
    SubPictureHD pic;
    subPictures.clear();

    try
    {
        while (index < bufsize)
        {
            if (subtitleProcessor->isCancelled())
            {
                throw QString("Cancelled by user!");
            }
            emit currentProgressChanged(index);

            if (fileBuffer->getWord(index) != 0x5350)
            {
                throw QString("ID 'SP' missing at index ").arg(QString::number(index, 16), 8, QChar('0'));
            }
            int masterIndex = index + 10; //end of header
            pic = SubPictureHD();
            // hard code size since it's not part of the format???
            pic.setScreenWidth(1920);
            pic.setScreenHeight(1080);

            subtitleProcessor->printX(QString("#%1\n").arg(QString::number(subPictures.size() + 1)));;

            pic.setStartTime(fileBuffer->getDWordLE(index += 2)); // read PTS
            int packetSize = fileBuffer->getDWord(index += 10);
            // offset to command buffer
            int ofsCmd = fileBuffer->getDWord(index += 4) + masterIndex;
            pic.setImageBufferSize(ofsCmd - (index + 4));
            index  = ofsCmd;
            int dcsq = fileBuffer->getWord(index);
            pic.setStartTime(pic.startTime() + (dcsq * 1024));

            subtitleProcessor->printX(QString("DCSQ start    ofs: %1  (%2)\n")
                                      .arg(QString::number(index, 16), 8, QChar('0'))
                                      .arg(TimeUtil::ptsToTimeStr(pic.startTime())));

            index+=2; // 2 bytes: dcsq
            int nextIndex = fileBuffer->getDWord(index) + masterIndex; // offset to next dcsq
            index += 5;  // 4 bytes: offset, 1 byte: start
            int cmd = 0;
            bool stopDisplay = false;
            bool stopCommand = false;
            int alphaSum = 0;
            int minAlphaSum = 256 * 256; // 256 fully transparent entries
            while (!stopDisplay)
            {
                cmd = fileBuffer->getByte(index++);
                switch (cmd)
                {
                case 0x01:
                {
                    subtitleProcessor->printX(QString("DCSQ start    ofs: %1  (%2)\n")
                                              .arg(QString::number(index, 16), 8, QChar('0'))
                                              .arg(TimeUtil::ptsToTimeStr(pic.startTime() + (dcsq * 1024))));
                    subtitleProcessor->printWarning("DCSQ start ignored due to missing DCSQ stop\n");
                } break;
                case 0x02:
                {
                    stopDisplay = true;
                    pic.setEndTime(pic.startTime() + (dcsq * 1024));

                    subtitleProcessor->printX(QString("DCSQ stop     ofs: %1  (%2)\n")
                                              .arg(QString::number(index, 16), 8, QChar('0'))
                                              .arg(TimeUtil::ptsToTimeStr(pic.endTime())));
                } break;
                case 0x83: // palette
                {
                    subtitleProcessor->print(QString("Palette info  ofs: %1\n").arg(QString::number(index, 16), 8, QChar('0')));

                    pic.setPaletteOffset(index);
                    index += 0x300;
                } break;
                case 0x84: // alpha
                {
                    subtitleProcessor->print(QString("Alpha info    ofs: %1\n").arg(QString::number(index, 16), 8, QChar('0')));                alphaSum = 0;

                    for (int i = index; i < index + 0x100; ++i)
                    {
                        alphaSum += fileBuffer->getByte(i);
                    }
                    if (alphaSum < minAlphaSum)
                    {
                        pic.setAlphaOffset(index);
                        minAlphaSum = alphaSum;
                    }
                    else
                    {
                        subtitleProcessor->printWarning(QString("Found faded alpha buffer -> alpha buffer skipped\n"));
                    }
                    index += 0x100;
                } break;
                case 0x85: // area
                {
                    pic.setX((fileBuffer->getByte(index) << 4) | (fileBuffer->getByte(index + 1) >> 4));
                    int imageWidth = (((fileBuffer->getByte(index + 1) &0xf) << 8) | (fileBuffer->getByte(index + 2)));
                    pic.setImageWidth((imageWidth - pic.x()) + 1);
                    pic.setY((fileBuffer->getByte(index + 3) <<4 ) | (fileBuffer->getByte(index + 4) >> 4));
                    int imageHeight = (((fileBuffer->getByte(index + 4) &0xf) << 8) | (fileBuffer->getByte(index + 5)));
                    pic.setImageHeight((imageHeight - pic.y()) + 1);

                    subtitleProcessor->print(QString("Area info     ofs: %1  (%2, %3) - (%4, %5)\n")
                                             .arg(QString::number(index, 16), 8, QChar('0'))
                                             .arg(QString::number(pic.x()))
                                             .arg(QString::number(pic.y()))
                                             .arg(QString::number(pic.x() + pic.imageWidth()))
                                             .arg(QString::number(pic.y() + pic.imageHeight())));

                    index += 6;
                } break;
                case 0x86: // even/odd offsets
                {
                    pic.setImageBufferOffsetEven(fileBuffer->getDWord(index) + masterIndex);
                    pic.setImageBufferOffsetOdd(fileBuffer->getDWord(index + 4) + masterIndex);

                    subtitleProcessor->print(QString("RLE buffers   ofs: %1  (even: %2, odd: %3)\n")
                                             .arg(QString::number(index, 16), 8, QChar('0'))
                                             .arg(QString::number(pic.imageBufferOffsetEven(), 16), 8, QChar('0'))
                                             .arg(QString::number(pic.imageBufferOffsetOdd(), 16), 8, QChar('0')));

                    index += 8;
                } break;
                case 0xff:
                {
                    if (stopCommand)
                    {
                        subtitleProcessor->printWarning(QString("DCSQ stop missing.\n"));

                        for (++index; index < bufsize; ++index)
                        {
                            if (fileBuffer->getByte(index++) != 0xff)
                            {
                                index--;
                                break;
                            }
                        }
                        stopDisplay = true;
                    } else {
                        index = nextIndex;
                        // add to display time
                        int d = fileBuffer->getWord(index);
                        dcsq = d;
                        nextIndex = fileBuffer->getDWord(index + 2) + masterIndex;
                        stopCommand = (index == nextIndex);

                        subtitleProcessor->print(QString("DCSQ          ofs: %1  (%2ms),    next DCSQ at ofs: %3\n")
                                                 .arg(QString::number(index, 16), 8, QChar('0'))
                                                 .arg(QString::number((d * 1024) / 90))
                                                 .arg(QString::number(nextIndex, 16), 8, QChar('0')));

                        index += 6;
                    }
                } break;
                default:
                {
                    throw QString("Unexpected command %1 at index %2").arg(cmd).arg(QString::number(index, 16), 8, QChar('0'));
                }
                }
            }
            index = masterIndex + packetSize;
            subPictures.push_back(pic);
        }
    }
    catch (QString e)
    {
        if (subPictures.size() == 0)
        {
            throw e;
        }
        subtitleProcessor->printError(QString(e + "\n"));
        subtitleProcessor->print(QString("Probably not all caption imported due to error.\n"));
    }

    emit currentProgressChanged(bufsize);
}

void SupHD::decode(SubPictureHD &subPicture)
{
    _palette = decodePalette(subPicture);
    _bitmap = decodeImage(subPicture, _palette.transparentIndex());
    _primaryColorIndex = _bitmap.primaryColorIndex(_palette, subtitleProcessor->getAlphaThreshold());
}

void SupHD::decodeLine(QImage &trg, int trgOfs, int width, int maxPixels, BitStream* src)
{
    int x = 0;
    int pixelsLeft = 0;
    int sumPixels = 0;
    bool lf = false;

    while (src->bitsLeft() > 0 && sumPixels < maxPixels)
    {
        int rleType = src->readBits(1);
        int colorType = src->readBits(1);
        int color;
        int numPixels;

        if (colorType == 1)
        {
            color = src->readBits(8);
        }
        else
        {
            color = src->readBits(2); // Colors between 0 and 3 are stored in two bits
        }

        if (rleType == 1)
        {
            int rleSize = src->readBits(1);
            if (rleSize == 1)
            {
                numPixels = src->readBits(7) + 9;
                if (numPixels == 9)
                {
                    numPixels = width - x;
                }
            }
            else
            {
                numPixels = src->readBits(3) + 2;
            }
        }
        else
        {
            numPixels = 1;
        }

        if ((x + numPixels) == width)
        {
            src->syncToByte();
            lf = true;
        }
        sumPixels += numPixels;

        // write pixels to target
        if ((x + numPixels) > width)
        {
            pixelsLeft = (x + numPixels) - width;
            numPixels = width - x;
            lf = true;
        }
        else
        {
            pixelsLeft = 0;
        }

        uchar* pixels = trg.bits();
        for (int i = 0; i < numPixels; ++i)
        {
            pixels[trgOfs + x + i] = (uchar)color;
        }

        if (lf == true)
        {
            trgOfs += ((x + numPixels + (trg.bytesPerLine() - (x + numPixels)))
                    + (width + (trg.bytesPerLine() - width))); // skip odd/even line
            x = pixelsLeft;
            lf = false;
        }
        else
        {
            x += numPixels;
        }

        // copy remaining pixels to new line
        for (int i = 0; i < pixelsLeft; ++i)
        {
            pixels[trgOfs + i] = (uchar)color;
        }
    }
}

Palette SupHD::decodePalette(SubPictureHD &subPicture)
{
    int ofs = subPicture.paletteOffset();
    int alphaOfs = subPicture.alphaOffset();

    Palette palette(256);
    for (int i = 0; i < palette.size(); ++i)
    {
        // each palette entry consists of 3 bytes
        int y = fileBuffer->getByte(ofs++);
        int cr, cb;
        if (subtitleProcessor->getSwapCrCb())
        {
            cb = fileBuffer->getByte(ofs++);
            cr = fileBuffer->getByte(ofs++);
        }
        else
        {
            cr = fileBuffer->getByte(ofs++);
            cb = fileBuffer->getByte(ofs++);
        }
        // each alpha entry consists of 1 byte
        int alpha = 0xff - fileBuffer->getByte(alphaOfs++);
        if (alpha < subtitleProcessor->getAlphaCrop()) // to not mess with scaling algorithms, make transparent color black
        {
            palette.setRGB(i, qRgb(0, 0, 0));
        }
        else
        {
            palette.setYCbCr(i, y, cb, cr);
        }
        palette.setAlpha(i, alpha);
    }
    return palette;
}

Bitmap SupHD::decodeImage(SubPictureHD &subPicture, int transparentIndex)
{
    int w = subPicture.imageWidth();
    int h = subPicture.imageHeight();
    int warnings = 0;

    if (w > subPicture.screenWidth() || h > subPicture.screenHeight())
    {
        throw QString("Subpicture too large: %1x%2 at offset %3")
                .arg(QString::number(w))
                .arg(QString::number(h))
                .arg(QString::number(subPicture.imageBufferOffsetEven(), 16), 8, QChar('0'));
    }

    Bitmap bm(w, h, transparentIndex);

    int sizeEven = subPicture.imageBufferOffsetOdd() - subPicture.imageBufferOffsetEven();
    int sizeOdd = (subPicture.imageBufferSize() + subPicture.imageBufferOffsetEven()) - subPicture.imageBufferOffsetOdd();

    if (sizeEven <= 0 || sizeOdd <= 0)
    {
        throw QString("Corrupt buffer offset information");
    }

    QVector<uchar> evenBuf = QVector<uchar>(sizeEven);
    QVector<uchar> oddBuf  = QVector<uchar>(sizeOdd);

    for (int i = 0; i < evenBuf.size(); i++)
    {
        evenBuf.replace(i, (uchar)fileBuffer->getByte(subPicture.imageBufferOffsetEven() + i));
    }
    for (int i = 0; i < oddBuf.size(); ++i)
    {
        oddBuf.replace(i, (uchar)fileBuffer->getByte(subPicture.imageBufferOffsetOdd() + i));
    }
    // decode even lines
    BitStream even = BitStream(evenBuf);
    decodeLine(bm.image(), 0, w, w * ((h / 2) + (h & 1)), &even);
    // decode odd lines
    BitStream odd  = BitStream(oddBuf);
    decodeLine(bm.image(), w + (bm.image().bytesPerLine() - w), w, (h / 2) * w, &odd);

    if (warnings > 0)
    {
        subtitleProcessor->printWarning(QString("problems during RLE decoding of picture at offset %1\n")
                                        .arg(QString::number(subPicture.imageBufferOffsetEven(), 16), 8, QChar('0')));
    }

    return bm;
}
<commit_msg>Change to set window sizes instead of using setX, setY, setImageWidth, setImageHeight.<commit_after>/*
 * BDSup2Sub++ (C) 2012 Adam T.
 * Based on code from BDSup2Sub by Copyright 2009 Volker Oth (0xdeadbeef)
 * and Copyright 2012 Miklos Juhasz (mjuhasz)
 *
 *
 * 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 "suphd.h"
#include "subtitleprocessor.h"
#include "subpicturehd.h"
#include "Tools/filebuffer.h"
#include "Tools/bitstream.h"
#include "Tools/timeutil.h"
#include "bitmap.h"
#include "palette.h"
#include <QImage>

SupHD::SupHD(QString fileName, SubtitleProcessor *subtitleProcessor) :
    supFileName(fileName)
{
    this->subtitleProcessor = subtitleProcessor;
}

SupHD::~SupHD()
{
    if (!fileBuffer.isNull())
    {
        fileBuffer.reset();
    }
}

QImage SupHD::image()
{
    return _bitmap.image(_palette);
}

QImage SupHD::image(Bitmap &bitmap)
{
    return bitmap.image(_palette);
}

void SupHD::decode(int index)
{
    if (index < subPictures.size())
    {
        decode(subPictures[index]);
    }
    else
    {
        throw QString("Index: %1 out of bounds.\n").arg(QString::number(index));
    }
}

int SupHD::numFrames()
{
    return subPictures.size();
}

qint64 SupHD::endTime(int index)
{
    return subPictures[index].endTime();
}

qint64 SupHD::startTime(int index)
{
    return subPictures[index].startTime();
}

qint64 SupHD::startOffset(int index)
{
    return subPictures[index].imageBufferOffsetEven();
}

SubPicture *SupHD::subPicture(int index)
{
    return &subPictures[index];
}

void SupHD::readAllSupFrames()
{
    fileBuffer.reset(new FileBuffer(supFileName));

    int index = 0;
    int bufsize = (int)fileBuffer->getSize();
    SubPictureHD pic;
    subPictures.clear();

    try
    {
        while (index < bufsize)
        {
            if (subtitleProcessor->isCancelled())
            {
                throw QString("Cancelled by user!");
            }
            emit currentProgressChanged(index);

            if (fileBuffer->getWord(index) != 0x5350)
            {
                throw QString("ID 'SP' missing at index ").arg(QString::number(index, 16), 8, QChar('0'));
            }
            int masterIndex = index + 10; //end of header
            pic = SubPictureHD();
            // hard code size since it's not part of the format???
            pic.setScreenWidth(1920);
            pic.setScreenHeight(1080);

            subtitleProcessor->printX(QString("#%1\n").arg(QString::number(subPictures.size() + 1)));;

            pic.setStartTime(fileBuffer->getDWordLE(index += 2)); // read PTS
            int packetSize = fileBuffer->getDWord(index += 10);
            // offset to command buffer
            int ofsCmd = fileBuffer->getDWord(index += 4) + masterIndex;
            pic.setImageBufferSize(ofsCmd - (index + 4));
            index  = ofsCmd;
            int dcsq = fileBuffer->getWord(index);
            pic.setStartTime(pic.startTime() + (dcsq * 1024));

            subtitleProcessor->printX(QString("DCSQ start    ofs: %1  (%2)\n")
                                      .arg(QString::number(index, 16), 8, QChar('0'))
                                      .arg(TimeUtil::ptsToTimeStr(pic.startTime())));

            index+=2; // 2 bytes: dcsq
            int nextIndex = fileBuffer->getDWord(index) + masterIndex; // offset to next dcsq
            index += 5;  // 4 bytes: offset, 1 byte: start
            int cmd = 0;
            bool stopDisplay = false;
            bool stopCommand = false;
            int alphaSum = 0;
            int minAlphaSum = 256 * 256; // 256 fully transparent entries
            while (!stopDisplay)
            {
                cmd = fileBuffer->getByte(index++);
                switch (cmd)
                {
                case 0x01:
                {
                    subtitleProcessor->printX(QString("DCSQ start    ofs: %1  (%2)\n")
                                              .arg(QString::number(index, 16), 8, QChar('0'))
                                              .arg(TimeUtil::ptsToTimeStr(pic.startTime() + (dcsq * 1024))));
                    subtitleProcessor->printWarning("DCSQ start ignored due to missing DCSQ stop\n");
                } break;
                case 0x02:
                {
                    stopDisplay = true;
                    pic.setEndTime(pic.startTime() + (dcsq * 1024));

                    subtitleProcessor->printX(QString("DCSQ stop     ofs: %1  (%2)\n")
                                              .arg(QString::number(index, 16), 8, QChar('0'))
                                              .arg(TimeUtil::ptsToTimeStr(pic.endTime())));
                } break;
                case 0x83: // palette
                {
                    subtitleProcessor->print(QString("Palette info  ofs: %1\n").arg(QString::number(index, 16), 8, QChar('0')));

                    pic.setPaletteOffset(index);
                    index += 0x300;
                } break;
                case 0x84: // alpha
                {
                    subtitleProcessor->print(QString("Alpha info    ofs: %1\n").arg(QString::number(index, 16), 8, QChar('0')));                alphaSum = 0;

                    for (int i = index; i < index + 0x100; ++i)
                    {
                        alphaSum += fileBuffer->getByte(i);
                    }
                    if (alphaSum < minAlphaSum)
                    {
                        pic.setAlphaOffset(index);
                        minAlphaSum = alphaSum;
                    }
                    else
                    {
                        subtitleProcessor->printWarning(QString("Found faded alpha buffer -> alpha buffer skipped\n"));
                    }
                    index += 0x100;
                } break;
                case 0x85: // area
                {
                    int x = (fileBuffer->getByte(index) << 4) | (fileBuffer->getByte(index + 1) >> 4);
                    int imageWidth = (((fileBuffer->getByte(index + 1) &0xf) << 8) | (fileBuffer->getByte(index + 2)));
                    int y = (fileBuffer->getByte(index + 3) <<4 ) | (fileBuffer->getByte(index + 4) >> 4);
                    int imageHeight = (((fileBuffer->getByte(index + 4) &0xf) << 8) | (fileBuffer->getByte(index + 5)));

                    QVector<QRect> imageRects = { QRect(x,
                                                        y,
                                                        (imageWidth - pic.x()) + 1,
                                                        (imageHeight - pic.y()) + 1),
                                                };
                    pic.setWindowSizes(imageRects);

                    subtitleProcessor->print(QString("Area info     ofs: %1  (%2, %3) - (%4, %5)\n")
                                             .arg(QString::number(index, 16), 8, QChar('0'))
                                             .arg(QString::number(pic.x()))
                                             .arg(QString::number(pic.y()))
                                             .arg(QString::number(pic.x() + pic.imageWidth()))
                                             .arg(QString::number(pic.y() + pic.imageHeight())));

                    index += 6;
                } break;
                case 0x86: // even/odd offsets
                {
                    pic.setImageBufferOffsetEven(fileBuffer->getDWord(index) + masterIndex);
                    pic.setImageBufferOffsetOdd(fileBuffer->getDWord(index + 4) + masterIndex);

                    subtitleProcessor->print(QString("RLE buffers   ofs: %1  (even: %2, odd: %3)\n")
                                             .arg(QString::number(index, 16), 8, QChar('0'))
                                             .arg(QString::number(pic.imageBufferOffsetEven(), 16), 8, QChar('0'))
                                             .arg(QString::number(pic.imageBufferOffsetOdd(), 16), 8, QChar('0')));

                    index += 8;
                } break;
                case 0xff:
                {
                    if (stopCommand)
                    {
                        subtitleProcessor->printWarning(QString("DCSQ stop missing.\n"));

                        for (++index; index < bufsize; ++index)
                        {
                            if (fileBuffer->getByte(index++) != 0xff)
                            {
                                index--;
                                break;
                            }
                        }
                        stopDisplay = true;
                    } else {
                        index = nextIndex;
                        // add to display time
                        int d = fileBuffer->getWord(index);
                        dcsq = d;
                        nextIndex = fileBuffer->getDWord(index + 2) + masterIndex;
                        stopCommand = (index == nextIndex);

                        subtitleProcessor->print(QString("DCSQ          ofs: %1  (%2ms),    next DCSQ at ofs: %3\n")
                                                 .arg(QString::number(index, 16), 8, QChar('0'))
                                                 .arg(QString::number((d * 1024) / 90))
                                                 .arg(QString::number(nextIndex, 16), 8, QChar('0')));

                        index += 6;
                    }
                } break;
                default:
                {
                    throw QString("Unexpected command %1 at index %2").arg(cmd).arg(QString::number(index, 16), 8, QChar('0'));
                }
                }
            }
            index = masterIndex + packetSize;
            subPictures.push_back(pic);
        }
    }
    catch (QString e)
    {
        if (subPictures.size() == 0)
        {
            throw e;
        }
        subtitleProcessor->printError(QString(e + "\n"));
        subtitleProcessor->print(QString("Probably not all caption imported due to error.\n"));
    }

    emit currentProgressChanged(bufsize);
}

void SupHD::decode(SubPictureHD &subPicture)
{
    _palette = decodePalette(subPicture);
    _bitmap = decodeImage(subPicture, _palette.transparentIndex());
    _primaryColorIndex = _bitmap.primaryColorIndex(_palette, subtitleProcessor->getAlphaThreshold());
}

void SupHD::decodeLine(QImage &trg, int trgOfs, int width, int maxPixels, BitStream* src)
{
    int x = 0;
    int pixelsLeft = 0;
    int sumPixels = 0;
    bool lf = false;

    while (src->bitsLeft() > 0 && sumPixels < maxPixels)
    {
        int rleType = src->readBits(1);
        int colorType = src->readBits(1);
        int color;
        int numPixels;

        if (colorType == 1)
        {
            color = src->readBits(8);
        }
        else
        {
            color = src->readBits(2); // Colors between 0 and 3 are stored in two bits
        }

        if (rleType == 1)
        {
            int rleSize = src->readBits(1);
            if (rleSize == 1)
            {
                numPixels = src->readBits(7) + 9;
                if (numPixels == 9)
                {
                    numPixels = width - x;
                }
            }
            else
            {
                numPixels = src->readBits(3) + 2;
            }
        }
        else
        {
            numPixels = 1;
        }

        if ((x + numPixels) == width)
        {
            src->syncToByte();
            lf = true;
        }
        sumPixels += numPixels;

        // write pixels to target
        if ((x + numPixels) > width)
        {
            pixelsLeft = (x + numPixels) - width;
            numPixels = width - x;
            lf = true;
        }
        else
        {
            pixelsLeft = 0;
        }

        uchar* pixels = trg.bits();
        for (int i = 0; i < numPixels; ++i)
        {
            pixels[trgOfs + x + i] = (uchar)color;
        }

        if (lf == true)
        {
            trgOfs += ((x + numPixels + (trg.bytesPerLine() - (x + numPixels)))
                    + (width + (trg.bytesPerLine() - width))); // skip odd/even line
            x = pixelsLeft;
            lf = false;
        }
        else
        {
            x += numPixels;
        }

        // copy remaining pixels to new line
        for (int i = 0; i < pixelsLeft; ++i)
        {
            pixels[trgOfs + i] = (uchar)color;
        }
    }
}

Palette SupHD::decodePalette(SubPictureHD &subPicture)
{
    int ofs = subPicture.paletteOffset();
    int alphaOfs = subPicture.alphaOffset();

    Palette palette(256);
    for (int i = 0; i < palette.size(); ++i)
    {
        // each palette entry consists of 3 bytes
        int y = fileBuffer->getByte(ofs++);
        int cr, cb;
        if (subtitleProcessor->getSwapCrCb())
        {
            cb = fileBuffer->getByte(ofs++);
            cr = fileBuffer->getByte(ofs++);
        }
        else
        {
            cr = fileBuffer->getByte(ofs++);
            cb = fileBuffer->getByte(ofs++);
        }
        // each alpha entry consists of 1 byte
        int alpha = 0xff - fileBuffer->getByte(alphaOfs++);
        if (alpha < subtitleProcessor->getAlphaCrop()) // to not mess with scaling algorithms, make transparent color black
        {
            palette.setRGB(i, qRgb(0, 0, 0));
        }
        else
        {
            palette.setYCbCr(i, y, cb, cr);
        }
        palette.setAlpha(i, alpha);
    }
    return palette;
}

Bitmap SupHD::decodeImage(SubPictureHD &subPicture, int transparentIndex)
{
    int w = subPicture.imageWidth();
    int h = subPicture.imageHeight();
    int warnings = 0;

    if (w > subPicture.screenWidth() || h > subPicture.screenHeight())
    {
        throw QString("Subpicture too large: %1x%2 at offset %3")
                .arg(QString::number(w))
                .arg(QString::number(h))
                .arg(QString::number(subPicture.imageBufferOffsetEven(), 16), 8, QChar('0'));
    }

    Bitmap bm(w, h, transparentIndex);

    int sizeEven = subPicture.imageBufferOffsetOdd() - subPicture.imageBufferOffsetEven();
    int sizeOdd = (subPicture.imageBufferSize() + subPicture.imageBufferOffsetEven()) - subPicture.imageBufferOffsetOdd();

    if (sizeEven <= 0 || sizeOdd <= 0)
    {
        throw QString("Corrupt buffer offset information");
    }

    QVector<uchar> evenBuf = QVector<uchar>(sizeEven);
    QVector<uchar> oddBuf  = QVector<uchar>(sizeOdd);

    for (int i = 0; i < evenBuf.size(); i++)
    {
        evenBuf.replace(i, (uchar)fileBuffer->getByte(subPicture.imageBufferOffsetEven() + i));
    }
    for (int i = 0; i < oddBuf.size(); ++i)
    {
        oddBuf.replace(i, (uchar)fileBuffer->getByte(subPicture.imageBufferOffsetOdd() + i));
    }
    // decode even lines
    BitStream even = BitStream(evenBuf);
    decodeLine(bm.image(), 0, w, w * ((h / 2) + (h & 1)), &even);
    // decode odd lines
    BitStream odd  = BitStream(oddBuf);
    decodeLine(bm.image(), w + (bm.image().bytesPerLine() - w), w, (h / 2) * w, &odd);

    if (warnings > 0)
    {
        subtitleProcessor->printWarning(QString("problems during RLE decoding of picture at offset %1\n")
                                        .arg(QString::number(subPicture.imageBufferOffsetEven(), 16), 8, QChar('0')));
    }

    return bm;
}
<|endoftext|>