<commit_before>//
//  FilteringSpeaker.h
//  Clock Signal
//
//  Created by Thomas Harte on 15/12/2017.
//  Copyright © 2017 Thomas Harte. All rights reserved.
//

#ifndef FilteringSpeaker_h
#define FilteringSpeaker_h

#include "../Speaker.hpp"
#include "../../../SignalProcessing/Stepper.hpp"
#include "../../../SignalProcessing/FIRFilter.hpp"
#include "../../../ClockReceiver/ClockReceiver.hpp"
#include "../../../Concurrency/AsyncTaskQueue.hpp"

#include <mutex>
#include <cstring>

namespace Outputs {
namespace Speaker {

/*!
	The low-pass speaker expects an Outputs::Speaker::SampleSource-derived
	template class, and uses the instance supplied to its constructor as the
	source of a high-frequency stream of audio which it filters down to a
	lower-frequency output.
*/
template <typename T> class LowpassSpeaker: public Speaker {
	public:
		LowpassSpeaker(T &sample_source) : sample_source_(sample_source) {
			sample_source.set_sample_volume_range(32767);
		}

		// Implemented as per Speaker.
		float get_ideal_clock_rate_in_range(float minimum, float maximum) {
			std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);

			// return twice the cut off, if applicable
			if(	filter_parameters_.high_frequency_cutoff > 0.0f &&
				filter_parameters_.input_cycles_per_second >= filter_parameters_.high_frequency_cutoff * 3.0f &&
				filter_parameters_.input_cycles_per_second <= filter_parameters_.high_frequency_cutoff * 3.0f)
					return filter_parameters_.high_frequency_cutoff * 3.0f;

			// return exactly the input rate if possible
			if(	filter_parameters_.input_cycles_per_second >= minimum &&
				filter_parameters_.input_cycles_per_second <= maximum)
					return filter_parameters_.input_cycles_per_second;

			// if the input rate is lower, return the minimum
			if(filter_parameters_.input_cycles_per_second < minimum)
				return minimum;

			// otherwise, return the maximum
			return maximum;
		}

		// Implemented as per Speaker.
		void set_output_rate(float cycles_per_second, int buffer_size) {
			std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
			filter_parameters_.output_cycles_per_second = cycles_per_second;
			filter_parameters_.parameters_are_dirty = true;
			output_buffer_.resize(static_cast<std::size_t>(buffer_size));
		}

		/*!
			Sets the clock rate of the input audio.
		*/
		void set_input_rate(float cycles_per_second) {
			std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
			filter_parameters_.input_cycles_per_second = cycles_per_second;
			filter_parameters_.parameters_are_dirty = true;
			filter_parameters_.input_rate_changed = true;
		}

		/*!
			Allows a cut-off frequency to be specified for audio. Ordinarily this low-pass speaker
			will determine a cut-off based on the output audio rate. A caller can manually select
			an alternative cut-off. This allows machines with a low-pass filter on their audio output
			path to be explicit about its effect, and get that simulation for free.
		*/
		void set_high_frequency_cutoff(float high_frequency) {
			std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
			filter_parameters_.high_frequency_cutoff = high_frequency;
			filter_parameters_.parameters_are_dirty = true;
		}

		/*!
			Advances by the number of cycles specified, obtaining data from the sample source supplied
			at construction, filtering it and passing it on to the speaker's delegate if there is one.
		*/
		void run_for(const Cycles cycles) {
			if(!delegate_) return;

			std::size_t cycles_remaining = static_cast<size_t>(cycles.as_int());
			if(!cycles_remaining) return;

			FilterParameters filter_parameters;
			{
				std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
				filter_parameters = filter_parameters_;
				filter_parameters_.parameters_are_dirty = false;
				filter_parameters_.input_rate_changed = false;
			}
			if(filter_parameters.parameters_are_dirty) update_filter_coefficients(filter_parameters);
			if(filter_parameters.input_rate_changed) {
				delegate_->speaker_did_change_input_clock(this);
			}

			// If input and output rates exactly match, and no additional cut-off has been specified,
			// just accumulate results and pass on.
			if(	filter_parameters.input_cycles_per_second == filter_parameters.output_cycles_per_second &&
				filter_parameters.high_frequency_cutoff < 0.0) {
				while(cycles_remaining) {
					std::size_t cycles_to_read = std::min(output_buffer_.size() - output_buffer_pointer_, cycles_remaining);

					sample_source_.get_samples(cycles_to_read, &output_buffer_[output_buffer_pointer_]);
					output_buffer_pointer_ += cycles_to_read;

					// announce to delegate if full
					if(output_buffer_pointer_ == output_buffer_.size()) {
						output_buffer_pointer_ = 0;
						delegate_->speaker_did_complete_samples(this, output_buffer_);
					}

					cycles_remaining -= cycles_to_read;
				}

				return;
			}

			// if the output rate is less than the input rate, or an additional cut-off has been specified, use the filter.
			if(	filter_parameters.input_cycles_per_second > filter_parameters.output_cycles_per_second ||
				(filter_parameters.input_cycles_per_second == filter_parameters.output_cycles_per_second && filter_parameters.high_frequency_cutoff >= 0.0)) {
				while(cycles_remaining) {
					std::size_t cycles_to_read = std::min(cycles_remaining, input_buffer_.size() - input_buffer_depth_);
					sample_source_.get_samples(cycles_to_read, &input_buffer_[input_buffer_depth_]);
					cycles_remaining -= cycles_to_read;
					input_buffer_depth_ += cycles_to_read;

					if(input_buffer_depth_ == input_buffer_.size()) {
						output_buffer_[output_buffer_pointer_] = filter_->apply(input_buffer_.data());
						output_buffer_pointer_++;

						// Announce to delegate if full.
						if(output_buffer_pointer_ == output_buffer_.size()) {
							output_buffer_pointer_ = 0;
							delegate_->speaker_did_complete_samples(this, output_buffer_);
						}

						// If the next loop around is going to reuse some of the samples just collected, use a memmove to
						// preserve them in the correct locations (TODO: use a longer buffer to fix that) and don't skip
						// anything. Otherwise skip as required to get to the next sample batch and don't expect to reuse.
						uint64_t steps = stepper_->step();
						if(steps < input_buffer_.size()) {
							int16_t *input_buffer = input_buffer_.data();
							std::memmove(	input_buffer,
											&input_buffer[steps],
											sizeof(int16_t) * (input_buffer_.size() - steps));
							input_buffer_depth_ -= steps;
						} else {
							if(steps > input_buffer_.size())
								sample_source_.skip_samples(steps - input_buffer_.size());
							input_buffer_depth_ = 0;
						}
					}
				}

				return;
			}

			// TODO: input rate is less than output rate
		}

		/*!
			Provides a convenience shortcut for deferring a call to run_for.
		*/
		void run_for(Concurrency::DeferringAsyncTaskQueue &queue, const Cycles cycles) {
			queue.defer([this, cycles] {
				run_for(cycles);
			});
		}

	private:
		T &sample_source_;

		std::size_t output_buffer_pointer_ = 0;
		std::size_t input_buffer_depth_ = 0;
		std::vector<int16_t> input_buffer_;
		std::vector<int16_t> output_buffer_;

		std::unique_ptr<SignalProcessing::Stepper> stepper_;
		std::unique_ptr<SignalProcessing::FIRFilter> filter_;

		std::mutex filter_parameters_mutex_;
		struct FilterParameters {
			float input_cycles_per_second = 0.0f;
			float output_cycles_per_second = 0.0f;
			float high_frequency_cutoff = -1.0;

			bool parameters_are_dirty = true;
			bool input_rate_changed = false;
		} filter_parameters_;

		void update_filter_coefficients(const FilterParameters &filter_parameters) {
			// Make a guess at a good number of taps.
			std::size_t number_of_taps = static_cast<std::size_t>(
				ceilf((filter_parameters.input_cycles_per_second + filter_parameters.output_cycles_per_second) / filter_parameters.output_cycles_per_second)
			);
			number_of_taps = (number_of_taps * 2) | 1;

			output_buffer_pointer_ = 0;

			stepper_.reset(new SignalProcessing::Stepper(
				static_cast<uint64_t>(filter_parameters.input_cycles_per_second),
				static_cast<uint64_t>(filter_parameters.output_cycles_per_second)));

			float high_pass_frequency = filter_parameters.output_cycles_per_second / 2.0f;
			if(filter_parameters.high_frequency_cutoff > 0.0) {
				high_pass_frequency = std::min(filter_parameters.output_cycles_per_second / 2.0f, high_pass_frequency);
			}
			filter_.reset(new SignalProcessing::FIRFilter(
				static_cast<unsigned int>(number_of_taps),
				filter_parameters.input_cycles_per_second,
				0.0,
				high_pass_frequency,
				SignalProcessing::FIRFilter::DefaultAttenuation));

			input_buffer_.resize(static_cast<std::size_t>(number_of_taps));
			input_buffer_depth_ = 0;
		}
};

}
}

#endif /* FilteringSpeaker_h */
<commit_msg>Ensures artificial frequency limits are honoured.<commit_after>//
//  FilteringSpeaker.h
//  Clock Signal
//
//  Created by Thomas Harte on 15/12/2017.
//  Copyright © 2017 Thomas Harte. All rights reserved.
//

#ifndef FilteringSpeaker_h
#define FilteringSpeaker_h

#include "../Speaker.hpp"
#include "../../../SignalProcessing/Stepper.hpp"
#include "../../../SignalProcessing/FIRFilter.hpp"
#include "../../../ClockReceiver/ClockReceiver.hpp"
#include "../../../Concurrency/AsyncTaskQueue.hpp"

#include <mutex>
#include <cstring>

namespace Outputs {
namespace Speaker {

/*!
	The low-pass speaker expects an Outputs::Speaker::SampleSource-derived
	template class, and uses the instance supplied to its constructor as the
	source of a high-frequency stream of audio which it filters down to a
	lower-frequency output.
*/
template <typename T> class LowpassSpeaker: public Speaker {
	public:
		LowpassSpeaker(T &sample_source) : sample_source_(sample_source) {
			sample_source.set_sample_volume_range(32767);
		}

		// Implemented as per Speaker.
		float get_ideal_clock_rate_in_range(float minimum, float maximum) {
			std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);

			// return twice the cut off, if applicable
			if(	filter_parameters_.high_frequency_cutoff > 0.0f &&
				filter_parameters_.input_cycles_per_second >= filter_parameters_.high_frequency_cutoff * 3.0f &&
				filter_parameters_.input_cycles_per_second <= filter_parameters_.high_frequency_cutoff * 3.0f)
					return filter_parameters_.high_frequency_cutoff * 3.0f;

			// return exactly the input rate if possible
			if(	filter_parameters_.input_cycles_per_second >= minimum &&
				filter_parameters_.input_cycles_per_second <= maximum)
					return filter_parameters_.input_cycles_per_second;

			// if the input rate is lower, return the minimum
			if(filter_parameters_.input_cycles_per_second < minimum)
				return minimum;

			// otherwise, return the maximum
			return maximum;
		}

		// Implemented as per Speaker.
		void set_output_rate(float cycles_per_second, int buffer_size) {
			std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
			filter_parameters_.output_cycles_per_second = cycles_per_second;
			filter_parameters_.parameters_are_dirty = true;
			output_buffer_.resize(static_cast<std::size_t>(buffer_size));
		}

		/*!
			Sets the clock rate of the input audio.
		*/
		void set_input_rate(float cycles_per_second) {
			std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
			filter_parameters_.input_cycles_per_second = cycles_per_second;
			filter_parameters_.parameters_are_dirty = true;
			filter_parameters_.input_rate_changed = true;
		}

		/*!
			Allows a cut-off frequency to be specified for audio. Ordinarily this low-pass speaker
			will determine a cut-off based on the output audio rate. A caller can manually select
			an alternative cut-off. This allows machines with a low-pass filter on their audio output
			path to be explicit about its effect, and get that simulation for free.
		*/
		void set_high_frequency_cutoff(float high_frequency) {
			std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
			filter_parameters_.high_frequency_cutoff = high_frequency;
			filter_parameters_.parameters_are_dirty = true;
		}

		/*!
			Advances by the number of cycles specified, obtaining data from the sample source supplied
			at construction, filtering it and passing it on to the speaker's delegate if there is one.
		*/
		void run_for(const Cycles cycles) {
			if(!delegate_) return;

			std::size_t cycles_remaining = static_cast<size_t>(cycles.as_int());
			if(!cycles_remaining) return;

			FilterParameters filter_parameters;
			{
				std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
				filter_parameters = filter_parameters_;
				filter_parameters_.parameters_are_dirty = false;
				filter_parameters_.input_rate_changed = false;
			}
			if(filter_parameters.parameters_are_dirty) update_filter_coefficients(filter_parameters);
			if(filter_parameters.input_rate_changed) {
				delegate_->speaker_did_change_input_clock(this);
			}

			// If input and output rates exactly match, and no additional cut-off has been specified,
			// just accumulate results and pass on.
			if(	filter_parameters.input_cycles_per_second == filter_parameters.output_cycles_per_second &&
				filter_parameters.high_frequency_cutoff < 0.0) {
				while(cycles_remaining) {
					std::size_t cycles_to_read = std::min(output_buffer_.size() - output_buffer_pointer_, cycles_remaining);

					sample_source_.get_samples(cycles_to_read, &output_buffer_[output_buffer_pointer_]);
					output_buffer_pointer_ += cycles_to_read;

					// announce to delegate if full
					if(output_buffer_pointer_ == output_buffer_.size()) {
						output_buffer_pointer_ = 0;
						delegate_->speaker_did_complete_samples(this, output_buffer_);
					}

					cycles_remaining -= cycles_to_read;
				}

				return;
			}

			// if the output rate is less than the input rate, or an additional cut-off has been specified, use the filter.
			if(	filter_parameters.input_cycles_per_second > filter_parameters.output_cycles_per_second ||
				(filter_parameters.input_cycles_per_second == filter_parameters.output_cycles_per_second && filter_parameters.high_frequency_cutoff >= 0.0)) {
				while(cycles_remaining) {
					std::size_t cycles_to_read = std::min(cycles_remaining, input_buffer_.size() - input_buffer_depth_);
					sample_source_.get_samples(cycles_to_read, &input_buffer_[input_buffer_depth_]);
					cycles_remaining -= cycles_to_read;
					input_buffer_depth_ += cycles_to_read;

					if(input_buffer_depth_ == input_buffer_.size()) {
						output_buffer_[output_buffer_pointer_] = filter_->apply(input_buffer_.data());
						output_buffer_pointer_++;

						// Announce to delegate if full.
						if(output_buffer_pointer_ == output_buffer_.size()) {
							output_buffer_pointer_ = 0;
							delegate_->speaker_did_complete_samples(this, output_buffer_);
						}

						// If the next loop around is going to reuse some of the samples just collected, use a memmove to
						// preserve them in the correct locations (TODO: use a longer buffer to fix that) and don't skip
						// anything. Otherwise skip as required to get to the next sample batch and don't expect to reuse.
						uint64_t steps = stepper_->step();
						if(steps < input_buffer_.size()) {
							int16_t *input_buffer = input_buffer_.data();
							std::memmove(	input_buffer,
											&input_buffer[steps],
											sizeof(int16_t) * (input_buffer_.size() - steps));
							input_buffer_depth_ -= steps;
						} else {
							if(steps > input_buffer_.size())
								sample_source_.skip_samples(steps - input_buffer_.size());
							input_buffer_depth_ = 0;
						}
					}
				}

				return;
			}

			// TODO: input rate is less than output rate
		}

		/*!
			Provides a convenience shortcut for deferring a call to run_for.
		*/
		void run_for(Concurrency::DeferringAsyncTaskQueue &queue, const Cycles cycles) {
			queue.defer([this, cycles] {
				run_for(cycles);
			});
		}

	private:
		T &sample_source_;

		std::size_t output_buffer_pointer_ = 0;
		std::size_t input_buffer_depth_ = 0;
		std::vector<int16_t> input_buffer_;
		std::vector<int16_t> output_buffer_;

		std::unique_ptr<SignalProcessing::Stepper> stepper_;
		std::unique_ptr<SignalProcessing::FIRFilter> filter_;

		std::mutex filter_parameters_mutex_;
		struct FilterParameters {
			float input_cycles_per_second = 0.0f;
			float output_cycles_per_second = 0.0f;
			float high_frequency_cutoff = -1.0;

			bool parameters_are_dirty = true;
			bool input_rate_changed = false;
		} filter_parameters_;

		void update_filter_coefficients(const FilterParameters &filter_parameters) {
			float high_pass_frequency = filter_parameters.output_cycles_per_second / 2.0f;
			if(filter_parameters.high_frequency_cutoff > 0.0) {
				high_pass_frequency = std::min(filter_parameters.high_frequency_cutoff, high_pass_frequency);
			}

			// Make a guess at a good number of taps.
			std::size_t number_of_taps = static_cast<std::size_t>(
				ceilf((filter_parameters.input_cycles_per_second + high_pass_frequency) / high_pass_frequency)
			);
			number_of_taps = (number_of_taps * 2) | 1;

			output_buffer_pointer_ = 0;
			stepper_.reset(new SignalProcessing::Stepper(
				static_cast<uint64_t>(filter_parameters.input_cycles_per_second),
				static_cast<uint64_t>(filter_parameters.output_cycles_per_second)));

			filter_.reset(new SignalProcessing::FIRFilter(
				static_cast<unsigned int>(number_of_taps),
				filter_parameters.input_cycles_per_second,
				0.0,
				high_pass_frequency,
				SignalProcessing::FIRFilter::DefaultAttenuation));

			input_buffer_.resize(static_cast<std::size_t>(number_of_taps));
			input_buffer_depth_ = 0;
		}
};

}
}

#endif /* FilteringSpeaker_h */
<|endoftext|>


<commit_before>#include "TEntryListArray.h"
#include "TLeaf.h"
#include "TROOT.h"
#include "TTree.h"
#include "TTreeReader.h"
#include "TTreeReaderValue.h"
#include "TTreeReaderArray.h"

#include "gtest/gtest.h"
#include <stdlib.h>

TTree* MakeTree() {
   double x[3]{};
   float z = 0.;
   struct {
      unsigned int ny;
      int* y = nullptr;
   } yData;
   std::string str;
   Double32_t Double32 = 12.;
   Float16_t Float16 = -12.;

   TTree* tree = new TTree("T", "test tree");
   tree->Branch("one", &x, "x[3]/D");
   tree->Branch("two", &yData, "ny/i:y[ny]/I");
   tree->Branch("three", &z, "z");
   tree->Branch("str", &str);
   tree->Branch("d32", &Double32);
   tree->Branch("f16", &Float16);

   x[1] = 42.;
   yData.ny = 42;
   yData.y = new int[42]{};
   yData.y[0] = 17;
   str = "first";
   tree->Fill();

   x[2] = 43.;
   yData.ny = 5;
   yData.y[4] = 7;
   str = "";
   tree->Fill();

   for (int entry = 2; entry < 20; ++entry) {
      z = entry * (1 - 2 * (entry % 2)); // +entry for even, -entry for odd
      str = std::string(entry, '*');
      tree->Fill();
   }

   delete [] yData.y;

   tree->ResetBranchAddresses();

   return tree;
}

TEST(TTreeReaderBasic, Interfaces) {
   TTree* tree = MakeTree();

   TTreeReader tr(tree);
   TTreeReaderArray<double> x(tr, "one.x");
   TTreeReaderArray<int> y(tr, "two.y");
   TTreeReaderValue<unsigned int> ny(tr, "two.ny");
   TTreeReaderValue<std::string> nstr(tr, "str");

   // Before reading data:
   EXPECT_NE(tr.begin(), tr.end());
   //MISSING: EXPECT_EQ(2, tr.end() - tr.begin());
   EXPECT_EQ(-1, tr.GetCurrentEntry());
   EXPECT_EQ(20, tr.GetEntries(false));
   EXPECT_EQ(TTreeReader::kEntryNotLoaded, tr.GetEntryStatus());
   EXPECT_EQ(tree, tr.GetTree());
   EXPECT_FALSE(tr.IsChain());

   EXPECT_EQ(nullptr, ny.GetAddress());
   EXPECT_FALSE(ny.IsValid());
   EXPECT_STREQ("two.ny", ny.GetBranchName());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kReadNothingYet, ny.GetReadStatus());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kSetupNotSetup, ny.GetSetupStatus());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kReadNothingYet, ny.ProxyRead());

   // Skip to second entry:
   EXPECT_TRUE(tr.Next());
   EXPECT_TRUE(tr.Next());

   EXPECT_NE(tr.begin(), tr.end());
   //MISSING: EXPECT_EQ(2, tr.end() - tr.begin());
   EXPECT_EQ(1, tr.GetCurrentEntry());
   EXPECT_EQ(20, tr.GetEntries(false));

   EXPECT_EQ(5u, *ny);
   EXPECT_NE(nullptr, ny.GetAddress());
   EXPECT_TRUE(ny.IsValid());
   EXPECT_EQ(ny.GetAddress(), ny.Get());
   EXPECT_STREQ("two", ny.GetBranchName());
   EXPECT_STREQ("ny", ny.GetLeaf()->GetName());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kReadSuccess, ny.GetReadStatus());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kSetupMatch, ny.GetSetupStatus());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kReadSuccess, ny.ProxyRead());

   EXPECT_EQ(3u, x.GetSize());
   EXPECT_EQ(5u, y.GetSize());
   EXPECT_DOUBLE_EQ(43., x[2]);
   //FAILS: EXPECT_EQ(7, y[4]);

   for (int entry = 2; entry < 20; ++entry)
      EXPECT_TRUE(tr.Next());

   EXPECT_FALSE(tr.Next());
   //FAILS: EXPECT_FALSE(ny.IsValid());
}

TEST(TTreeReaderBasic, ErrorProbing) {
   TTreeReader tr("doesNotExist", gROOT);
   EXPECT_EQ(TTreeReader::kEntryNoTree, tr.GetEntryStatus());
   EXPECT_EQ(nullptr, tr.GetTree());

   tr.SetTree((TTree*)nullptr);
   EXPECT_EQ(TTreeReader::kEntryNoTree, tr.GetEntryStatus());
   EXPECT_EQ(nullptr, tr.GetTree());

   TTreeReaderValue<double> val;
   EXPECT_FALSE(val.IsValid());
}

TEST(TTreeReaderBasic, Range) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);

   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(5, 8));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(5, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(6, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(7, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Reached end:
   EXPECT_FALSE(tr.Next());
   EXPECT_EQ(8, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryBeyondEnd, tr.GetEntryStatus());

   // Read beyond end:
   EXPECT_FALSE(tr.Next());
   EXPECT_EQ(TTreeReader::kEntryBeyondEnd, tr.GetEntryStatus());
   EXPECT_EQ(9, tr.GetCurrentEntry());
}

TEST(TTreeReaderBasic, InvalidRange) {
   TTree *tree = MakeTree();
   TTreeReader tr(tree);

   EXPECT_EQ(TTreeReader::kEntryNotFound, tr.SetEntriesRange(tree->GetEntries(), 0));

   // Is SetEntriesRange() simply ignored as it should be?
   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(0, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());
}

TEST(TTreeReaderBasic, OneEntryRange) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);

   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(1, 2));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(1, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Read beyond end:
   EXPECT_FALSE(tr.Next());
   EXPECT_EQ(TTreeReader::kEntryBeyondEnd, tr.GetEntryStatus());
   EXPECT_EQ(2, tr.GetCurrentEntry());

   for (int entry = 2; entry < tree->GetEntries(); ++entry)
      EXPECT_FALSE(tr.Next());
}

TEST(TTreeReaderBasic, ZeroEntryRange) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);

   // end is ignored:
   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(18, 18));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(18, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(19, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Read beyond end:
   EXPECT_FALSE(tr.Next());
   // As the TTree only has up to entry 19, 20 is kEntryNotFound:
   EXPECT_EQ(TTreeReader::kEntryNotFound, tr.GetEntryStatus());
   EXPECT_EQ(20, tr.GetCurrentEntry());
}

TEST(TTreeReaderBasic, InvertedEntryRange) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);

   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(18, 3));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(18, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(19, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Read beyond end:
   EXPECT_FALSE(tr.Next());
   // As the TTree only has up to entry 19, 20 is kEntryNotFound:
   EXPECT_EQ(TTreeReader::kEntryNotFound, tr.GetEntryStatus());
   EXPECT_EQ(20, tr.GetCurrentEntry());
}

TEST(TTreeReaderBasic, EntryList) {
   // See https://root.cern.ch/phpBB3/viewtopic.php?f=3&t=22850&p=100796
   TTree* tree = MakeTree();
   EXPECT_EQ(9, tree->Draw(">>negZ","three.z<0", "entrylistarray"));
   TEntryListArray* selected = (TEntryListArray*)gDirectory->Get("negZ");
   TTreeReader aReader(tree, selected);

   EXPECT_EQ(9, aReader.GetEntries(false));

   TTreeReaderValue<float> z(aReader, "three.z");

   int count = 0;
   while (aReader.Next()) {
      // Make sure all Next()-ed entries have z<0 as selected by the entry list.
      EXPECT_LT(*z, 0);
      ++count;
   }
   EXPECT_EQ(9, count);
}

TEST(TTreeReaderBasic, EntryListBeyondEnd) {
   TTree* tree = MakeTree();
   TEntryList selected;
   // Add the last valid entry; a subsequent Next() must return false.
   selected.Enter(tree->GetEntries() - 1);

   TTreeReader aReader(tree, &selected);

   EXPECT_EQ(1, aReader.GetEntries(false));

   EXPECT_TRUE(aReader.Next());
   EXPECT_EQ(0, aReader.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, aReader.GetEntryStatus());

   EXPECT_FALSE(aReader.Next());
   EXPECT_EQ(1, aReader.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryNotFound, aReader.GetEntryStatus());
}

TEST(TTreeReaderBasic, Values) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);
   TTreeReaderArray<double> x(tr, "one.x");
   TTreeReaderArray<int> y(tr, "two.y");
   TTreeReaderValue<unsigned int> ny(tr, "two.ny");
   TTreeReaderValue<std::string> str(tr, "str");
   TTreeReaderValue<Double32_t> d32(tr, "d32");
   TTreeReaderValue<Float16_t> f16(tr, "f16");

   // Check values for first entry.
   EXPECT_TRUE(tr.Next());

   EXPECT_DOUBLE_EQ(42, x[1]);
   EXPECT_EQ(42u, *ny);
   // FAILS! Already in TLeafI, fNData == 42 (good!) but GetValue(0) == 0.
   // EXPECT_EQ(17, y[0]);
   EXPECT_STREQ("first", str->c_str());
   EXPECT_FLOAT_EQ(12, *d32);
   EXPECT_FLOAT_EQ(-12, *f16);
}
<commit_msg>Test subsequent SetEntriesRange() / Restart() calls.<commit_after>#include "TEntryListArray.h"
#include "TLeaf.h"
#include "TROOT.h"
#include "TTree.h"
#include "TTreeReader.h"
#include "TTreeReaderValue.h"
#include "TTreeReaderArray.h"

#include "gtest/gtest.h"
#include <stdlib.h>

TTree* MakeTree() {
   double x[3]{};
   float z = 0.;
   struct {
      unsigned int ny;
      int* y = nullptr;
   } yData;
   std::string str;
   Double32_t Double32 = 12.;
   Float16_t Float16 = -12.;

   TTree* tree = new TTree("T", "test tree");
   tree->Branch("one", &x, "x[3]/D");
   tree->Branch("two", &yData, "ny/i:y[ny]/I");
   tree->Branch("three", &z, "z");
   tree->Branch("str", &str);
   tree->Branch("d32", &Double32);
   tree->Branch("f16", &Float16);

   x[1] = 42.;
   yData.ny = 42;
   yData.y = new int[42]{};
   yData.y[0] = 17;
   str = "first";
   tree->Fill();

   x[2] = 43.;
   yData.ny = 5;
   yData.y[4] = 7;
   str = "";
   tree->Fill();

   for (int entry = 2; entry < 20; ++entry) {
      z = entry * (1 - 2 * (entry % 2)); // +entry for even, -entry for odd
      str = std::string(entry, '*');
      tree->Fill();
   }

   delete [] yData.y;

   tree->ResetBranchAddresses();

   return tree;
}

TEST(TTreeReaderBasic, Interfaces) {
   TTree* tree = MakeTree();

   TTreeReader tr(tree);
   TTreeReaderArray<double> x(tr, "one.x");
   TTreeReaderArray<int> y(tr, "two.y");
   TTreeReaderValue<unsigned int> ny(tr, "two.ny");
   TTreeReaderValue<std::string> nstr(tr, "str");

   // Before reading data:
   EXPECT_NE(tr.begin(), tr.end());
   //MISSING: EXPECT_EQ(2, tr.end() - tr.begin());
   EXPECT_EQ(-1, tr.GetCurrentEntry());
   EXPECT_EQ(20, tr.GetEntries(false));
   EXPECT_EQ(TTreeReader::kEntryNotLoaded, tr.GetEntryStatus());
   EXPECT_EQ(tree, tr.GetTree());
   EXPECT_FALSE(tr.IsChain());

   EXPECT_EQ(nullptr, ny.GetAddress());
   EXPECT_FALSE(ny.IsValid());
   EXPECT_STREQ("two.ny", ny.GetBranchName());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kReadNothingYet, ny.GetReadStatus());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kSetupNotSetup, ny.GetSetupStatus());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kReadNothingYet, ny.ProxyRead());

   // Skip to second entry:
   EXPECT_TRUE(tr.Next());
   EXPECT_TRUE(tr.Next());

   EXPECT_NE(tr.begin(), tr.end());
   //MISSING: EXPECT_EQ(2, tr.end() - tr.begin());
   EXPECT_EQ(1, tr.GetCurrentEntry());
   EXPECT_EQ(20, tr.GetEntries(false));

   EXPECT_EQ(5u, *ny);
   EXPECT_NE(nullptr, ny.GetAddress());
   EXPECT_TRUE(ny.IsValid());
   EXPECT_EQ(ny.GetAddress(), ny.Get());
   EXPECT_STREQ("two", ny.GetBranchName());
   EXPECT_STREQ("ny", ny.GetLeaf()->GetName());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kReadSuccess, ny.GetReadStatus());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kSetupMatch, ny.GetSetupStatus());
   EXPECT_EQ(ROOT::Internal::TTreeReaderValueBase::kReadSuccess, ny.ProxyRead());

   EXPECT_EQ(3u, x.GetSize());
   EXPECT_EQ(5u, y.GetSize());
   EXPECT_DOUBLE_EQ(43., x[2]);
   //FAILS: EXPECT_EQ(7, y[4]);

   for (int entry = 2; entry < 20; ++entry)
      EXPECT_TRUE(tr.Next());

   EXPECT_FALSE(tr.Next());
   //FAILS: EXPECT_FALSE(ny.IsValid());
}

TEST(TTreeReaderBasic, ErrorProbing) {
   TTreeReader tr("doesNotExist", gROOT);
   EXPECT_EQ(TTreeReader::kEntryNoTree, tr.GetEntryStatus());
   EXPECT_EQ(nullptr, tr.GetTree());

   tr.SetTree((TTree*)nullptr);
   EXPECT_EQ(TTreeReader::kEntryNoTree, tr.GetEntryStatus());
   EXPECT_EQ(nullptr, tr.GetTree());

   TTreeReaderValue<double> val;
   EXPECT_FALSE(val.IsValid());
}

TEST(TTreeReaderBasic, Range) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);

   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(5, 8));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(5, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(6, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(7, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Reached end:
   EXPECT_FALSE(tr.Next());
   EXPECT_EQ(8, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryBeyondEnd, tr.GetEntryStatus());

   // Read beyond end:
   EXPECT_FALSE(tr.Next());
   EXPECT_EQ(TTreeReader::kEntryBeyondEnd, tr.GetEntryStatus());
   EXPECT_EQ(9, tr.GetCurrentEntry());

   // Restart, now with different entries.
   tr.Restart();
   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(0, 2));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(0, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(1, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Reached end:
   EXPECT_FALSE(tr.Next());
   EXPECT_EQ(2, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryBeyondEnd, tr.GetEntryStatus());

}

TEST(TTreeReaderBasic, InvalidRange) {
   TTree *tree = MakeTree();
   TTreeReader tr(tree);

   EXPECT_EQ(TTreeReader::kEntryNotFound, tr.SetEntriesRange(tree->GetEntries(), 0));

   // Is SetEntriesRange() simply ignored as it should be?
   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(0, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());
}

TEST(TTreeReaderBasic, OneEntryRange) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);

   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(1, 2));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(1, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Read beyond end:
   EXPECT_FALSE(tr.Next());
   EXPECT_EQ(TTreeReader::kEntryBeyondEnd, tr.GetEntryStatus());
   EXPECT_EQ(2, tr.GetCurrentEntry());

   for (int entry = 2; entry < tree->GetEntries(); ++entry)
      EXPECT_FALSE(tr.Next());
}

TEST(TTreeReaderBasic, ZeroEntryRange) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);

   // end is ignored:
   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(18, 18));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(18, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(19, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Read beyond end:
   EXPECT_FALSE(tr.Next());
   // As the TTree only has up to entry 19, 20 is kEntryNotFound:
   EXPECT_EQ(TTreeReader::kEntryNotFound, tr.GetEntryStatus());
   EXPECT_EQ(20, tr.GetCurrentEntry());
}

TEST(TTreeReaderBasic, InvertedEntryRange) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);

   EXPECT_EQ(TTreeReader::kEntryValid, tr.SetEntriesRange(18, 3));

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(18, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   EXPECT_TRUE(tr.Next());
   EXPECT_EQ(19, tr.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, tr.GetEntryStatus());

   // Read beyond end:
   EXPECT_FALSE(tr.Next());
   // As the TTree only has up to entry 19, 20 is kEntryNotFound:
   EXPECT_EQ(TTreeReader::kEntryNotFound, tr.GetEntryStatus());
   EXPECT_EQ(20, tr.GetCurrentEntry());
}

TEST(TTreeReaderBasic, EntryList) {
   // See https://root.cern.ch/phpBB3/viewtopic.php?f=3&t=22850&p=100796
   TTree* tree = MakeTree();
   EXPECT_EQ(9, tree->Draw(">>negZ","three.z<0", "entrylistarray"));
   TEntryListArray* selected = (TEntryListArray*)gDirectory->Get("negZ");
   TTreeReader aReader(tree, selected);

   EXPECT_EQ(9, aReader.GetEntries(false));

   TTreeReaderValue<float> z(aReader, "three.z");

   int count = 0;
   while (aReader.Next()) {
      // Make sure all Next()-ed entries have z<0 as selected by the entry list.
      EXPECT_LT(*z, 0);
      ++count;
   }
   EXPECT_EQ(9, count);
}

TEST(TTreeReaderBasic, EntryListBeyondEnd) {
   TTree* tree = MakeTree();
   TEntryList selected;
   // Add the last valid entry; a subsequent Next() must return false.
   selected.Enter(tree->GetEntries() - 1);

   TTreeReader aReader(tree, &selected);

   EXPECT_EQ(1, aReader.GetEntries(false));

   EXPECT_TRUE(aReader.Next());
   EXPECT_EQ(0, aReader.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryValid, aReader.GetEntryStatus());

   EXPECT_FALSE(aReader.Next());
   EXPECT_EQ(1, aReader.GetCurrentEntry());
   EXPECT_EQ(TTreeReader::kEntryNotFound, aReader.GetEntryStatus());
}

TEST(TTreeReaderBasic, Values) {
   TTree* tree = MakeTree();
   TTreeReader tr(tree);
   TTreeReaderArray<double> x(tr, "one.x");
   TTreeReaderArray<int> y(tr, "two.y");
   TTreeReaderValue<unsigned int> ny(tr, "two.ny");
   TTreeReaderValue<std::string> str(tr, "str");
   TTreeReaderValue<Double32_t> d32(tr, "d32");
   TTreeReaderValue<Float16_t> f16(tr, "f16");

   // Check values for first entry.
   EXPECT_TRUE(tr.Next());

   EXPECT_DOUBLE_EQ(42, x[1]);
   EXPECT_EQ(42u, *ny);
   // FAILS! Already in TLeafI, fNData == 42 (good!) but GetValue(0) == 0.
   // EXPECT_EQ(17, y[0]);
   EXPECT_STREQ("first", str->c_str());
   EXPECT_FLOAT_EQ(12, *d32);
   EXPECT_FLOAT_EQ(-12, *f16);
}
<|endoftext|>


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

#include "powerMotor.h"

#include <trikKernel/configurer.h>

#include "mspI2cCommunicator.h"
#include "configurerHelper.h"

using namespace trikControl;

PowerMotor::PowerMotor(const QString &port, const trikKernel::Configurer &configurer
		, MspCommunicatorInterface &communicator)
	: mCommunicator(communicator)
	, mInvert(configurer.attributeByPort(port, "invert") == "false")
	, mCurrentPower(0)
	, mCurrentPeriod(0x1000)
	, mState("Power Motor on" + port)
{
	mMspCommandNumber = ConfigurerHelper::configureInt(configurer, mState, port, "i2cCommandNumber");
	mState.ready();
}

PowerMotor::~PowerMotor()
{
	if (mState.isReady()) {
		powerOff();
	}
}

PowerMotor::Status PowerMotor::status() const
{
	return combine(mCommunicator, mState.status());
}

void PowerMotor::setPower(int power, bool constrain)
{
	if (constrain) {
		if (power > 100)
		{
			power = 100;
		} else if (power < -100) {
			power = -100;
		}
	}

	mCurrentPower = power;

	power = mInvert ? -power : power;

	QByteArray command(3, '\0');
	command[0] = static_cast<char>(mMspCommandNumber & 0xFF);
	command[1] = static_cast<char>((mMspCommandNumber >> 8) & 0xFF);
	command[2] = static_cast<char>(power & 0xFF);

	mCommunicator.send(command);
}

int PowerMotor::power() const
{
	return mCurrentPower;
}

int PowerMotor::period() const
{
	return mCurrentPeriod;
}

void PowerMotor::powerOff()
{
	setPower(0);
}

void PowerMotor::setPeriod(int period)
{
	mCurrentPeriod = period;
	QByteArray command(3, '\0');
	command[0] = static_cast<char>((mMspCommandNumber - 4) & 0xFF);
	command[1] = static_cast<char>(period && 0xFF);
	command[2] = static_cast<char>(period >> 8);
	mCommunicator.send(command);
}
<commit_msg>Removed stopping of power motors from destructor<commit_after>/* Copyright 2013 - 2015 Yurii Litvinov and CyberTech Labs Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

#include "powerMotor.h"

#include <trikKernel/configurer.h>

#include "mspI2cCommunicator.h"
#include "configurerHelper.h"

using namespace trikControl;

PowerMotor::PowerMotor(const QString &port, const trikKernel::Configurer &configurer
		, MspCommunicatorInterface &communicator)
	: mCommunicator(communicator)
	, mInvert(configurer.attributeByPort(port, "invert") == "false")
	, mCurrentPower(0)
	, mCurrentPeriod(0x1000)
	, mState("Power Motor on" + port)
{
	mMspCommandNumber = ConfigurerHelper::configureInt(configurer, mState, port, "i2cCommandNumber");
	mState.ready();
}

PowerMotor::~PowerMotor()
{
}

PowerMotor::Status PowerMotor::status() const
{
	return combine(mCommunicator, mState.status());
}

void PowerMotor::setPower(int power, bool constrain)
{
	if (constrain) {
		if (power > 100)
		{
			power = 100;
		} else if (power < -100) {
			power = -100;
		}
	}

	mCurrentPower = power;

	power = mInvert ? -power : power;

	QByteArray command(3, '\0');
	command[0] = static_cast<char>(mMspCommandNumber & 0xFF);
	command[1] = static_cast<char>((mMspCommandNumber >> 8) & 0xFF);
	command[2] = static_cast<char>(power & 0xFF);

	mCommunicator.send(command);
}

int PowerMotor::power() const
{
	return mCurrentPower;
}

int PowerMotor::period() const
{
	return mCurrentPeriod;
}

void PowerMotor::powerOff()
{
	setPower(0);
}

void PowerMotor::setPeriod(int period)
{
	mCurrentPeriod = period;
	QByteArray command(3, '\0');
	command[0] = static_cast<char>((mMspCommandNumber - 4) & 0xFF);
	command[1] = static_cast<char>(period && 0xFF);
	command[2] = static_cast<char>(period >> 8);
	mCommunicator.send(command);
}
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2013-2020 Winlin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <srs_app_dtls.hpp>

using namespace std;

#include <string.h>

#include <srs_kernel_log.hpp>

#include <srtp2/srtp.h>

SrsDtls* SrsDtls::_instance = NULL;

SrsDtls::SrsDtls()
{
}

SrsDtls::~SrsDtls()
{
}

SrsDtls* SrsDtls::instance()
{
    if (!_instance) {
        _instance = new SrsDtls();
        _instance->init();
    }
    return _instance;
}

void SrsDtls::init()
{
    // srtp init first
    srs_assert(srtp_init() == 0);

    // init dtls context
	EVP_PKEY* dtls_private_key = EVP_PKEY_new();
    srs_assert(dtls_private_key);

    RSA* rsa = RSA_new();
    srs_assert(rsa);

    BIGNUM* exponent = BN_new();
    srs_assert(exponent);

    BN_set_word(exponent, RSA_F4);

	const std::string& aor = "www.hw.com";
	int expire_day = 365;
	int private_key_len = 1024;

    RSA_generate_key_ex(rsa, private_key_len, exponent, NULL);

    srs_assert(EVP_PKEY_set1_RSA(dtls_private_key, rsa) == 1);

    X509* dtls_cert = X509_new();
    srs_assert(dtls_cert);

    X509_NAME* subject = X509_NAME_new();
    srs_assert(subject);

    int serial = rand();
    ASN1_INTEGER_set(X509_get_serialNumber(dtls_cert), serial);

    X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *) aor.data(), aor.size(), -1, 0);

    X509_set_issuer_name(dtls_cert, subject);
    X509_set_subject_name(dtls_cert, subject);

    const long cert_duration = 60*60*24*expire_day;

    X509_gmtime_adj(X509_get_notBefore(dtls_cert), 0);
    X509_gmtime_adj(X509_get_notAfter(dtls_cert), cert_duration);

    srs_assert(X509_set_pubkey(dtls_cert, dtls_private_key) == 1);

    srs_assert(X509_sign(dtls_cert, dtls_private_key, EVP_sha1()) != 0);

    // cleanup
    RSA_free(rsa);
    BN_free(exponent);
    X509_NAME_free(subject);

    dtls_ctx = SSL_CTX_new(DTLS_method());
	srs_assert(SSL_CTX_use_certificate(dtls_ctx, dtls_cert) == 1);

    srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, dtls_private_key) == 1);
    srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") == 1);
    srs_assert(SSL_CTX_set_tlsext_use_srtp(dtls_ctx, "SRTP_AES128_CM_SHA1_80") == 0);

    SSL_CTX_set_verify_depth (dtls_ctx, 4);
    SSL_CTX_set_read_ahead(dtls_ctx, 1);

    // dtls fingerprint
    char fp[100] = {0};
    char *p = fp;
    unsigned char md[EVP_MAX_MD_SIZE];
    unsigned int n = 0;

    // TODO: FIXME: Unused variable.
    /*int r = */X509_digest(dtls_cert, EVP_sha256(), md, &n);

    for (unsigned int i = 0; i < n; i++, ++p) {
        sprintf(p, "%02X", md[i]);
        p += 2;

        if(i < (n-1)) {
            *p = ':';
        } else {
            *p = '\0';
        }
    }

    fingerprint.assign(fp, strlen(fp));
    srs_trace("fingerprint=%s", fingerprint.c_str());
}
<commit_msg>For RTC, verify peer and accept all certificate.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2013-2020 Winlin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <srs_app_dtls.hpp>

using namespace std;

#include <string.h>

#include <srs_kernel_log.hpp>

#include <srtp2/srtp.h>

SrsDtls* SrsDtls::_instance = NULL;

SrsDtls::SrsDtls()
{
}

SrsDtls::~SrsDtls()
{
}

SrsDtls* SrsDtls::instance()
{
    if (!_instance) {
        _instance = new SrsDtls();
        _instance->init();
    }
    return _instance;
}

// The return value of verify_callback controls the strategy of the further verification process. If verify_callback
// returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is
// set, a verification failure alert is sent to the peer and the TLS/SSL handshake is terminated. If verify_callback
// returns 1, the verification process is continued. If verify_callback always returns 1, the TLS/SSL handshake will
// not be terminated with respect to verification failures and the connection will be established. The calling process
// can however retrieve the error code of the last verification error using SSL_get_verify_result(3) or by maintaining
// its own error storage managed by verify_callback.
// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
    // Always OK, we don't check the certificate of client,
    // because we allow client self-sign certificate.
    return 1;
}

void SrsDtls::init()
{
    // srtp init first
    srs_assert(srtp_init() == 0);

    // init dtls context
	EVP_PKEY* dtls_private_key = EVP_PKEY_new();
    srs_assert(dtls_private_key);

    RSA* rsa = RSA_new();
    srs_assert(rsa);

    BIGNUM* exponent = BN_new();
    srs_assert(exponent);

    BN_set_word(exponent, RSA_F4);

	const std::string& aor = "www.hw.com";
	int expire_day = 365;
	int private_key_len = 1024;

    RSA_generate_key_ex(rsa, private_key_len, exponent, NULL);

    srs_assert(EVP_PKEY_set1_RSA(dtls_private_key, rsa) == 1);

    X509* dtls_cert = X509_new();
    srs_assert(dtls_cert);

    X509_NAME* subject = X509_NAME_new();
    srs_assert(subject);

    int serial = rand();
    ASN1_INTEGER_set(X509_get_serialNumber(dtls_cert), serial);

    X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *) aor.data(), aor.size(), -1, 0);

    X509_set_issuer_name(dtls_cert, subject);
    X509_set_subject_name(dtls_cert, subject);

    const long cert_duration = 60*60*24*expire_day;

    X509_gmtime_adj(X509_get_notBefore(dtls_cert), 0);
    X509_gmtime_adj(X509_get_notAfter(dtls_cert), cert_duration);

    srs_assert(X509_set_pubkey(dtls_cert, dtls_private_key) == 1);

    srs_assert(X509_sign(dtls_cert, dtls_private_key, EVP_sha1()) != 0);

    // cleanup
    RSA_free(rsa);
    BN_free(exponent);
    X509_NAME_free(subject);

    dtls_ctx = SSL_CTX_new(DTLS_method());
	srs_assert(SSL_CTX_use_certificate(dtls_ctx, dtls_cert) == 1);

    srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, dtls_private_key) == 1);
    srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") == 1);
    srs_assert(SSL_CTX_set_tlsext_use_srtp(dtls_ctx, "SRTP_AES128_CM_SHA1_80") == 0);

    // Server will send Certificate Request.
    // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
    // TODO: FIXME: Config it, default to off to make the packet smaller.
    SSL_CTX_set_verify(dtls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_callback);

    // The depth count is "level 0:peer certificate", "level 1: CA certificate",
    // "level 2: higher level CA certificate", and so on.
    // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
    SSL_CTX_set_verify_depth (dtls_ctx, 4);

    SSL_CTX_set_read_ahead(dtls_ctx, 1);

    // dtls fingerprint
    char fp[100] = {0};
    char *p = fp;
    unsigned char md[EVP_MAX_MD_SIZE];
    unsigned int n = 0;

    // TODO: FIXME: Unused variable.
    /*int r = */X509_digest(dtls_cert, EVP_sha256(), md, &n);

    for (unsigned int i = 0; i < n; i++, ++p) {
        sprintf(p, "%02X", md[i]);
        p += 2;

        if(i < (n-1)) {
            *p = ':';
        } else {
            *p = '\0';
        }
    }

    fingerprint.assign(fp, strlen(fp));
    srs_trace("fingerprint=%s", fingerprint.c_str());
}
<|endoftext|>


<commit_before>//__________________________________________________//
AliProtonAnalysis *GetProtonAnalysisObject(const char* analysisLevel = "ESD",
					   const char* esdAnalysisType = "Hybrid",
					   const char* pidMode = "Bayesian") {
  //Function to setup the AliProtonAnalysis object and return it
  AliProtonAnalysisBase *baseAnalysis = GetProtonAnalysisBaseObject(analysisLevel,esdAnalysisType,pidMode);

  AliProtonAnalysis *analysis = new AliProtonAnalysis();
  analysis->SetBaseAnalysis(baseAnalysis);
  if(baseAnalysis->GetEtaMode()) analysis->SetEtaMode();
  if(baseAnalysis->GetAnalysisMode() == AliProtonAnalysisBase::kGlobal) {
    Double_t gY[17] = {-0.9,-0.75,-0.6,-0.5,-0.4,-0.3,-0.2,-0.1,0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.75,0.9};
    Double_t gPt[18] = {0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.1,2.4,2.7,3.1};
    analysis->InitAnalysisHistograms(16,gY,17,gPt);
    //Double_t gPt[27] = {0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.1,2.4,2.7,3.0,3.4,3.8,4.2,4.7,5.1,6.0,7.0,9.0,12.0};
    //analysis->InitAnalysisHistograms(16,gY,26,gPt);
  }
  else
    analysis->InitAnalysisHistograms(baseAnalysis->GetNBinsX(),
				     baseAnalysis->GetMinX(),
				     baseAnalysis->GetMaxX(),
				     baseAnalysis->GetNBinsY(),
				     baseAnalysis->GetMinY(),
				     baseAnalysis->GetMaxY());

  return analysis;
}

//__________________________________________________//
AliProtonQAAnalysis *GetProtonQAAnalysisObject(const char* analysisLevel = "ESD",
					       const char* esdAnalysisType = "Hybrid",
					       const char* pidMode = "Bayesian") {
  //Function to setup the AliProtonQAAnalysis object and return it
  AliProtonAnalysisBase *baseAnalysis = GetProtonAnalysisBaseObject(analysisLevel,esdAnalysisType,pidMode);

  AliProtonQAAnalysis *analysis = new AliProtonQAAnalysis();
  analysis->SetBaseAnalysis(baseAnalysis);
  analysis->SetRunMCAnalysis();
  //analysis->SetMCProcessId(4);//4: weak decay - 13: hadronic interaction
  //analysis->SetMotherParticlePDGCode(3122);//3122: Lambda
  analysis->SetRunEfficiencyAnalysis(kFALSE);//use cuts in the eff. analysis
  analysis->SetQAYPtBins(baseAnalysis->GetNBinsX(),
			 baseAnalysis->GetMinX(),
			 baseAnalysis->GetMaxX(),
			 baseAnalysis->GetNBinsY(),
			 baseAnalysis->GetMinY(),
			 baseAnalysis->GetMaxY());

  return analysis;
}

//__________________________________________________//
AliProtonAnalysisBase *GetProtonAnalysisBaseObject(const char* analysisLevel = "ESD",
						   const char* esdAnalysisType = "Hybrid",
						   const char* pidMode = "Bayesian") {
  //Function to setup the AliProtonAnalysisBase object and return it
  AliProtonAnalysisBase *baseAnalysis = new AliProtonAnalysisBase();
  //baseAnalysis->SetDebugMode();
  baseAnalysis->SetAnalysisLevel(analysisLevel);
  if(analysisLevel == "ESD") {
    baseAnalysis->SetTriggerMode(AliProtonAnalysisBase::kMB2);
    baseAnalysis->SetMinTPCClusters(110);
    baseAnalysis->SetMaxChi2PerTPCCluster(2.2);
    baseAnalysis->SetMaxCov11(0.5);
    baseAnalysis->SetMaxCov22(0.5);
    baseAnalysis->SetMaxCov33(0.5);
    baseAnalysis->SetMaxCov44(0.5);
    baseAnalysis->SetMaxCov55(0.5);
    baseAnalysis->SetMinTPCdEdxPoints(80);
    switch(esdAnalysisType) {
    case "TPC":
      baseAnalysis->SetAnalysisMode(AliProtonAnalysisBase::kTPC);
      baseAnalysis->SetPhaseSpace(10, -0.5, 0.5, 16, 0.5, 0.9);
      baseAnalysis->SetTPCpid();
      baseAnalysis->SetMaxSigmaToVertexTPC(2.0);
      //baseAnalysis->SetMaxDCAXYTPC(1.5);
      //baseAnalysis->SetMaxDCAZTPC(1.5);
      break;
    case "Hybrid":
      baseAnalysis->SetAnalysisMode(AliProtonAnalysisBase::kHybrid);
      baseAnalysis->SetPhaseSpace(10, -0.5, 0.5, 16, 0.5, 0.9);
      baseAnalysis->SetTPCpid();
      baseAnalysis->SetMaxSigmaToVertex(2.0);
      /*baseAnalysis->SetMaxDCAXY(1.5);
	baseAnalysis->SetMaxDCAZ(1.5);*/
      baseAnalysis->SetPointOnITSLayer6();
      baseAnalysis->SetPointOnITSLayer5();
      //baseAnalysis->SetPointOnITSLayer4();
      //baseAnalysis->SetPointOnITSLayer3();
      baseAnalysis->SetPointOnITSLayer2();
      baseAnalysis->SetPointOnITSLayer1();
      baseAnalysis->SetMinITSClusters(4);
      break;
    case "Global":
      baseAnalysis->SetAnalysisMode(AliProtonAnalysisBase::kGlobal);
      baseAnalysis->SetPhaseSpace(20, -1.0, 1.0, 48, 0.3, 1.5);
      baseAnalysis->SetMaxSigmaToVertex(2.0);
      //baseAnalysis->SetMaxDCAXY(2.0);
      //baseAnalysis->SetMaxDCAZ(2.0);
      baseAnalysis->SetTPCRefit();
      baseAnalysis->SetPointOnITSLayer1();
      baseAnalysis->SetPointOnITSLayer2();
      //baseAnalysis->SetPointOnITSLayer3();
      //baseAnalysis->SetPointOnITSLayer4();
      baseAnalysis->SetPointOnITSLayer5();
      baseAnalysis->SetPointOnITSLayer6();
      baseAnalysis->SetMinITSClusters(5);
      baseAnalysis->SetITSRefit();
      baseAnalysis->SetESDpid();
      baseAnalysis->SetTOFpid();
      break;
    default:
      break;
    }
    baseAnalysis->SetAcceptedVertexDiamond(5.,5.,15.);
    baseAnalysis->SetEtaMode();
    switch(pidMode) {
    case "Bayesian":
      baseAnalysis->SetPIDMode(AliProtonAnalysisBase::kBayesian);
      //Momentum dependent priors
      /*TFile *f = TFile::Open("$ALICE_ROOT/PWG2/data/PriorProbabilities.root ");
	TF1 *fitElectrons = (TF1 *)f->Get("fitElectrons");
	TF1 *fitMuons = (TF1 *)f->Get("fitMuons");
	TF1 *fitPions = (TF1 *)f->Get("fitPions");
	TF1 *fitKaons = (TF1 *)f->Get("fitKaons");
	TF1 *fitProtons = (TF1 *)f->Get("fitProtons");
	baseAnalysis->SetPriorProbabilityFunctions(fitElectrons,
	fitMuons,
	fitPions,
	fitKaons,
	fitProtons);*/
      //Fixed prior probabilities
      Double_t partFrac[5] = {0.01, 0.01, 0.85, 0.10, 0.05};
      if(!baseAnalysis->IsPriorProbabilityFunctionUsed())
	baseAnalysis->SetPriorProbabilities(partFrac);
      break;
    case "Ratio":
      baseAnalysis->SetPIDMode(AliProtonAnalysisBase::kRatio);
      break;
    case "Sigma1":
      baseAnalysis->SetPIDMode(AliProtonAnalysisBase::kSigma1);
      baseAnalysis->SetNSigma(3);
      baseAnalysis->SetdEdxBandInfo("$ALICE_ROOT/PWG2/data/protonsdEdxInfo.dat");
      break;
    case "Sigma2":
      baseAnalysis->SetPIDMode(AliProtonAnalysisBase::kSigma2);
      baseAnalysis->SetNSigma(3);
      baseAnalysis->SetdEdxBandInfo("$ALICE_ROOT/PWG2/data/protonsdEdxInfo.dat");
      break;
    default:
      break;
    }//PID mode
  }//ESD
  if(analysisLevel == "MC")
    baseAnalysis->SetPhaseSpace(10, -0.5, 0.5, 16, 0.5, 0.9);

  return baseAnalysis;
}
<commit_msg>Modification in the config file<commit_after>//__________________________________________________//
AliProtonAnalysis *GetProtonAnalysisObject(const char* analysisLevel = "ESD",
					   const char* esdAnalysisType = "Hybrid",
					   const char* pidMode = "Bayesian") {
  //Function to setup the AliProtonAnalysis object and return it
  AliProtonAnalysisBase *baseAnalysis = GetProtonAnalysisBaseObject(analysisLevel,esdAnalysisType,pidMode);

  AliProtonAnalysis *analysis = new AliProtonAnalysis();
  analysis->SetBaseAnalysis(baseAnalysis);
  if(baseAnalysis->GetAnalysisMode() == AliProtonAnalysisBase::kGlobal) {
    Double_t gY[17] = {-0.9,-0.75,-0.6,-0.5,-0.4,-0.3,-0.2,-0.1,0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.75,0.9};
    Double_t gPt[18] = {0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.1,2.4,2.7,3.1};
    analysis->InitAnalysisHistograms(16,gY,17,gPt);
    //Double_t gPt[27] = {0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.1,2.4,2.7,3.0,3.4,3.8,4.2,4.7,5.1,6.0,7.0,9.0,12.0};
    //analysis->InitAnalysisHistograms(16,gY,26,gPt);
  }
  else
    analysis->InitAnalysisHistograms(baseAnalysis->GetNBinsX(),
				     baseAnalysis->GetMinX(),
				     baseAnalysis->GetMaxX(),
				     baseAnalysis->GetNBinsY(),
				     baseAnalysis->GetMinY(),
				     baseAnalysis->GetMaxY());

  return analysis;
}

//__________________________________________________//
AliProtonQAAnalysis *GetProtonQAAnalysisObject(const char* analysisLevel = "ESD",
					       const char* esdAnalysisType = "Hybrid",
					       const char* pidMode = "Bayesian") {
  //Function to setup the AliProtonQAAnalysis object and return it
  AliProtonAnalysisBase *baseAnalysis = GetProtonAnalysisBaseObject(analysisLevel,esdAnalysisType,pidMode);

  AliProtonQAAnalysis *analysis = new AliProtonQAAnalysis();
  analysis->SetBaseAnalysis(baseAnalysis);
  analysis->SetRunMCAnalysis();
  //analysis->SetMCProcessId(4);//4: weak decay - 13: hadronic interaction
  //analysis->SetMotherParticlePDGCode(3122);//3122: Lambda
  analysis->SetRunEfficiencyAnalysis(kFALSE);//use cuts in the eff. analysis
  analysis->SetQAYPtBins(baseAnalysis->GetNBinsX(),
			 baseAnalysis->GetMinX(),
			 baseAnalysis->GetMaxX(),
			 baseAnalysis->GetNBinsY(),
			 baseAnalysis->GetMinY(),
			 baseAnalysis->GetMaxY());

  return analysis;
}

//__________________________________________________//
AliProtonAnalysisBase *GetProtonAnalysisBaseObject(const char* analysisLevel = "ESD",
						   const char* esdAnalysisType = "Hybrid",
						   const char* pidMode = "Bayesian") {
  //Function to setup the AliProtonAnalysisBase object and return it
  AliProtonAnalysisBase *baseAnalysis = new AliProtonAnalysisBase();
  //baseAnalysis->SetDebugMode();
  baseAnalysis->SetAnalysisLevel(analysisLevel);
  if(analysisLevel == "ESD") {
    baseAnalysis->SetTriggerMode(AliProtonAnalysisBase::kMB2);
    baseAnalysis->SetMinTPCClusters(110);
    baseAnalysis->SetMaxChi2PerTPCCluster(2.2);
    baseAnalysis->SetMaxCov11(0.5);
    baseAnalysis->SetMaxCov22(0.5);
    baseAnalysis->SetMaxCov33(0.5);
    baseAnalysis->SetMaxCov44(0.5);
    baseAnalysis->SetMaxCov55(0.5);
    baseAnalysis->SetMinTPCdEdxPoints(80);
    switch(esdAnalysisType) {
    case "TPC":
      baseAnalysis->SetAnalysisMode(AliProtonAnalysisBase::kTPC);
      baseAnalysis->SetPhaseSpace(10, -0.5, 0.5, 16, 0.5, 0.9);
      baseAnalysis->SetTPCpid();
      baseAnalysis->SetMaxSigmaToVertexTPC(2.0);
      //baseAnalysis->SetMaxDCAXYTPC(1.5);
      //baseAnalysis->SetMaxDCAZTPC(1.5);
      break;
    case "Hybrid":
      baseAnalysis->SetAnalysisMode(AliProtonAnalysisBase::kHybrid);
      baseAnalysis->SetPhaseSpace(10, -0.5, 0.5, 16, 0.5, 0.9);
      baseAnalysis->SetTPCpid();
      baseAnalysis->SetMaxSigmaToVertex(2.0);
      /*baseAnalysis->SetMaxDCAXY(1.5);
	baseAnalysis->SetMaxDCAZ(1.5);*/
      baseAnalysis->SetPointOnITSLayer6();
      baseAnalysis->SetPointOnITSLayer5();
      //baseAnalysis->SetPointOnITSLayer4();
      //baseAnalysis->SetPointOnITSLayer3();
      baseAnalysis->SetPointOnITSLayer2();
      baseAnalysis->SetPointOnITSLayer1();
      baseAnalysis->SetMinITSClusters(4);
      break;
    case "Global":
      baseAnalysis->SetAnalysisMode(AliProtonAnalysisBase::kGlobal);
      baseAnalysis->SetPhaseSpace(20, -1.0, 1.0, 48, 0.3, 1.5);
      baseAnalysis->SetMaxSigmaToVertex(2.0);
      //baseAnalysis->SetMaxDCAXY(2.0);
      //baseAnalysis->SetMaxDCAZ(2.0);
      baseAnalysis->SetTPCRefit();
      baseAnalysis->SetPointOnITSLayer1();
      baseAnalysis->SetPointOnITSLayer2();
      //baseAnalysis->SetPointOnITSLayer3();
      //baseAnalysis->SetPointOnITSLayer4();
      baseAnalysis->SetPointOnITSLayer5();
      baseAnalysis->SetPointOnITSLayer6();
      baseAnalysis->SetMinITSClusters(5);
      baseAnalysis->SetITSRefit();
      baseAnalysis->SetESDpid();
      baseAnalysis->SetTOFpid();
      break;
    default:
      break;
    }
    baseAnalysis->SetAcceptedVertexDiamond(5.,5.,15.);
    baseAnalysis->SetEtaMode();
    switch(pidMode) {
    case "Bayesian":
      baseAnalysis->SetPIDMode(AliProtonAnalysisBase::kBayesian);
      //Momentum dependent priors
      /*TFile *f = TFile::Open("$ALICE_ROOT/PWG2/data/PriorProbabilities.root ");
	TF1 *fitElectrons = (TF1 *)f->Get("fitElectrons");
	TF1 *fitMuons = (TF1 *)f->Get("fitMuons");
	TF1 *fitPions = (TF1 *)f->Get("fitPions");
	TF1 *fitKaons = (TF1 *)f->Get("fitKaons");
	TF1 *fitProtons = (TF1 *)f->Get("fitProtons");
	baseAnalysis->SetPriorProbabilityFunctions(fitElectrons,
	fitMuons,
	fitPions,
	fitKaons,
	fitProtons);*/
      //Fixed prior probabilities
      Double_t partFrac[5] = {0.01, 0.01, 0.85, 0.10, 0.05};
      if(!baseAnalysis->IsPriorProbabilityFunctionUsed())
	baseAnalysis->SetPriorProbabilities(partFrac);
      break;
    case "Ratio":
      baseAnalysis->SetPIDMode(AliProtonAnalysisBase::kRatio);
      break;
    case "Sigma1":
      baseAnalysis->SetPIDMode(AliProtonAnalysisBase::kSigma1);
      baseAnalysis->SetNSigma(3);
      baseAnalysis->SetdEdxBandInfo("$ALICE_ROOT/PWG2/data/protonsdEdxInfo.dat");
      break;
    case "Sigma2":
      baseAnalysis->SetPIDMode(AliProtonAnalysisBase::kSigma2);
      baseAnalysis->SetNSigma(3);
      baseAnalysis->SetdEdxBandInfo("$ALICE_ROOT/PWG2/data/protonsdEdxInfo.dat");
      break;
    default:
      break;
    }//PID mode
  }//ESD
  if(analysisLevel == "MC")
    baseAnalysis->SetPhaseSpace(10, -0.5, 0.5, 16, 0.5, 0.9);

  return baseAnalysis;
}
<|endoftext|>


<commit_before>
void InitHistograms(AliDielectron *die, Int_t cutDefinition);
void InitCF(AliDielectron* die, Int_t cutDefinition);

void SetupTrackCuts(AliDielectron *die, Int_t cutDefinition);
void SetupPairCuts(AliDielectron *die, Int_t cutDefinition);

AliESDtrackCuts *SetupESDtrackCuts(Int_t cutDefinition);
/*
trackQ+Pt>1GeV+|TPCnSigE|<3
trackQ+PID1
trackQ+PID6
trackQ+PID7
trackQ+Pt>.5GeV
*/
TString names=("trackQ+Pt>1GeV+|TPCnSigE|<3;trackQ+PID1;trackQ+PID6;trackQ+PID7;trackQ+Pt>.5GeV");
TObjArray *arrNames=names.Tokenize(";");

const Int_t nDie=arrNames->GetEntries();

AliDielectron* ConfigJpsi2ee(Int_t cutDefinition)
{
  //
  // Setup the instance of AliDielectron
  //

  // create the actual framework object
  TString name=Form("%02d",cutDefinition);
  if (cutDefinition<arrNames->GetEntriesFast()){
    name=arrNames->At(cutDefinition)->GetName();
  }
  AliDielectron *die =
    new AliDielectron(Form("%s",name.Data()),
                      Form("Track cuts: %s",name.Data()));

  // cut setup
  SetupTrackCuts(die,cutDefinition);
  SetupPairCuts(die,cutDefinition);

  //
  // histogram setup
  // only if an AliDielectronHistos object is attached to the
  //  dielectron framework the QA histograms will be filled
  //
  InitHistograms(die,cutDefinition);

  // the last definition uses no cuts and only the QA histograms should be filled!
//   if (cutDefinition<nDie-1) InitCF(die,cutDefinition);

  return die;
}

//______________________________________________________________________________________
void SetupTrackCuts(AliDielectron *die, Int_t cutDefinition)
{
  //
  // Setup the track cuts
  //

  //ESD quality cuts
  die->GetTrackFilter().AddCuts(SetupESDtrackCuts(cutDefinition));

  //QA no CF
  if (cutDefinition==nDie-1) {
    //Pt cut
    AliDielectronVarCuts *pt = new AliDielectronVarCuts("Pt>.5","Pt>.5");
    pt->AddCut(AliDielectronVarManager::kPt,.5,1e30);
    die->GetTrackFilter().AddCuts(pt);

    return;
  }

  // pt + 3 sigma ele TPC
  if (cutDefinition==0){
    AliDielectronVarCuts *pt = new AliDielectronVarCuts("Pt>1+|TPCnSigE|<3","Pt>1+|TPCnSigE|<3");
    pt->AddCut(AliDielectronVarManager::kPt,1.,1e30);
    pt->AddCut(AliDielectronVarManager::kTPCnSigmaEle, -3., 3.);
    die->GetTrackFilter().AddCuts(pt);
  }

  //PID 1
  if (cutDefinition==0){
    AliDielectronPID *pid=new AliDielectronPID("pid1","pid1");
    pid->SetDefaults(1);
    die->GetTrackFilter().AddCuts(pid);
  }

  //PID 6
  if (cutDefinition==1){
    AliDielectronPID *pid=new AliDielectronPID("pid6","pid6");
    pid->SetDefaults(6);
    die->GetTrackFilter().AddCuts(pid);
  }

  //PID 7
  if (cutDefinition==2){
    AliDielectronPID *pid=new AliDielectronPID("pid7","pid7");
    pid->SetDefaults(7);
    die->GetTrackFilter().AddCuts(pid);
  }

}

//______________________________________________________________________________________
void SetupPairCuts(AliDielectron *die, Int_t cutDefinition)
{
  //
  // Setup the pair cuts
  //

  // reject conversions
  // and select mass region
  AliDielectronVarCuts *openingAngleCut=new AliDielectronVarCuts("OpeningAngle","Opening angle > 35mrad");
  openingAngleCut->AddCut(AliDielectronVarManager::kOpeningAngle,.035,4.);
  openingAngleCut->AddCut(AliDielectronVarManager::kM,2.,4.);
  die->GetPairFilter().AddCuts(openingAngleCut);
}

//______________________________________________________________________________________
AliESDtrackCuts *SetupESDtrackCuts(Int_t cutDefinition)
{
  //
  // Setup default AliESDtrackCuts
  //
  AliESDtrackCuts *esdTrackCuts = new AliESDtrackCuts;

  esdTrackCuts->SetMaxDCAToVertexZ(3.0);
  esdTrackCuts->SetMaxDCAToVertexXY(.07);
  esdTrackCuts->SetRequireTPCRefit(kTRUE);
  esdTrackCuts->SetRequireITSRefit(kTRUE);
  esdTrackCuts->SetAcceptKinkDaughters(kFALSE);
  esdTrackCuts->SetClusterRequirementITS(AliESDtrackCuts::kSPD,AliESDtrackCuts::kFirst);

  esdTrackCuts->SetMinNClustersTPC(110);
  esdTrackCuts->SetMaxChi2PerClusterTPC(4);

  return esdTrackCuts;
}

//______________________________________________________________________________________
void InitHistograms(AliDielectron *die, Int_t cutDefinition)
{
  //
  // Initialise the QA histograms
  //

  //Setup QA histograms
  AliDielectronHistos *histos=
    new AliDielectronHistos(die->GetName(),
                            die->GetTitle());

  //Initialise histogram classes
  histos->SetReservedWords("Track;Pair");

  //Event class (only for last QA)
  if (cutDefinition==nDie-1) histos->AddClass("Event");

  //Track classes, only first event
  for (Int_t i=0; i<2; ++i){
    histos->AddClass(Form("Track_%s",AliDielectron::TrackClassName(i)));
  }

  //Pair classes, only first event
  for (Int_t i=0; i<3; ++i){
    histos->AddClass(Form("Pair_%s",AliDielectron::PairClassName(i)));
  }

  //Event histograms
  if (cutDefinition==nDie-1){
    //add histograms to event class
    histos->UserHistogram("Event","nEvents","Number of processed events after cuts;Number events",
                          1,0.,1.,AliDielectronVarManager::kNevents);
  }

  //add histograms to Track classes
  histos->UserHistogram("Track","Pt","Pt;Pt [GeV];#tracks",200,0,20.,AliDielectronVarManager::kPt);
  histos->UserHistogram("Track","dEdx_P","dEdx;P [GeV];TPC signal (arb units);#tracks",
                        400,0.2,20.,200,0.,200.,AliDielectronVarManager::kPIn,AliDielectronVarManager::kTPCsignal,kTRUE);
  histos->UserHistogram("Track","TPCnSigmaEle_P","TPC number of sigmas Electrons;P [GeV];TPC number of sigmas Electrons;#tracks",
                        400,0.2,20.,100,-5.,5.,AliDielectronVarManager::kPIn,AliDielectronVarManager::kTPCnSigmaEle,kTRUE);
  histos->UserHistogram("Track","TPCnSigmaPio_P","TPC number of sigmas Pions;P [GeV];TPC number of sigmas Pions;#tracks",
                        400,0.2,20.,100,-5.,5.,AliDielectronVarManager::kPIn,AliDielectronVarManager::kTPCnSigmaPio,kTRUE);
  histos->UserHistogram("Track","dXY","dXY;dXY [cm];#tracks",200,-2.,2.,AliDielectronVarManager::kImpactParXY);

  //add histograms to Pair classes
  histos->UserHistogram("Pair","InvMass","Inv.Mass;Inv. Mass [GeV];#pairs",
                        500,0.,4.,AliDielectronVarManager::kM);
  histos->UserHistogram("Pair","Rapidity","Rapidity;Rapidity;#pairs",
                        100,-2.,2.,AliDielectronVarManager::kY);
  histos->UserHistogram("Pair","OpeningAngle","Opening angle;angle",
                        100,0.,3.15,AliDielectronVarManager::kOpeningAngle);
  histos->UserHistogram("Pair","Chi2/NDF","#Chi^{2}/NDF;#Chi^{2}/NDF",
                        100, 0., 20., AliDielectronVarManager::kChi2NDF);

  die->SetHistogramManager(histos);
}

void InitCF(AliDielectron* die, Int_t cutDefinition)
{
  //
  // Setupd the CF Manager if needed
  //
  AliDielectronCF *cf=new AliDielectronCF(die->GetName(),die->GetTitle());

  //pair variables
  cf->AddVariable(AliDielectronVarManager::kPt,20,0,10);
  cf->AddVariable(AliDielectronVarManager::kY,40,-2,2);
  cf->AddVariable(AliDielectronVarManager::kM,200,-0.01,3.99);
  cf->AddVariable(AliDielectronVarManager::kPairType,10,0,10);
  //leg variables
  cf->AddVariable(AliDielectronVarManager::kPt,20,0,10,kTRUE);

  //only in this case write MC truth info
  cf->SetStepsForCutsIncreasing();
  if (cutDefinition==0){
    cf->SetStepForMCtruth();
  }

  die->SetCFManagerPair(cf);
}
<commit_msg>- update Config<commit_after>
void InitHistograms(AliDielectron *die, Int_t cutDefinition);
void InitCF(AliDielectron* die, Int_t cutDefinition);

void SetupTrackCuts(AliDielectron *die, Int_t cutDefinition);
void SetupPairCuts(AliDielectron *die, Int_t cutDefinition);

AliESDtrackCuts *SetupESDtrackCuts(Int_t cutDefinition);
/*
trackQ+Pt>1GeV+|TPCnSigE|<3
trackQ+PID1
trackQ+PID6
trackQ+PID7
trackQ+Pt>.5GeV
*/
TString names=("trackQ+Pt>1GeV+|TPCnSigE|<3;trackQ+PID1;trackQ+PID6;trackQ+PID7;trackQ+Pt>.5GeV");
TObjArray *arrNames=names.Tokenize(";");

const Int_t nDie=arrNames->GetEntries();

AliDielectron* ConfigJpsi2ee(Int_t cutDefinition)
{
  //
  // Setup the instance of AliDielectron
  //

  // create the actual framework object
  TString name=Form("%02d",cutDefinition);
  if (cutDefinition<arrNames->GetEntriesFast()){
    name=arrNames->At(cutDefinition)->GetName();
  }
  AliDielectron *die =
    new AliDielectron(Form("%s",name.Data()),
                      Form("Track cuts: %s",name.Data()));

  // cut setup
  SetupTrackCuts(die,cutDefinition);
  SetupPairCuts(die,cutDefinition);

  //
  // histogram setup
  // only if an AliDielectronHistos object is attached to the
  //  dielectron framework the QA histograms will be filled
  //
  InitHistograms(die,cutDefinition);

  // the last definition uses no cuts and only the QA histograms should be filled!
//   if (cutDefinition<nDie-1) InitCF(die,cutDefinition);

  return die;
}

//______________________________________________________________________________________
void SetupTrackCuts(AliDielectron *die, Int_t cutDefinition)
{
  //
  // Setup the track cuts
  //

  //ESD quality cuts
  die->GetTrackFilter().AddCuts(SetupESDtrackCuts(cutDefinition));

  //QA no CF
  if (cutDefinition==nDie-1) {
    //Pt cut
    AliDielectronVarCuts *pt = new AliDielectronVarCuts("Pt>.5","Pt>.5");
    pt->AddCut(AliDielectronVarManager::kPt,.5,1e30);
    die->GetTrackFilter().AddCuts(pt);

    return;
  }

  // pt + 3 sigma ele TPC
  if (cutDefinition==0){
    AliDielectronVarCuts *pt = new AliDielectronVarCuts("Pt>1+|TPCnSigE|<3","Pt>1+|TPCnSigE|<3");
    pt->AddCut(AliDielectronVarManager::kPt,1.,1e30);
    pt->AddCut(AliDielectronVarManager::kTPCnSigmaEle, -3., 3.);
    die->GetTrackFilter().AddCuts(pt);
  }

  //PID 1
  if (cutDefinition==1){
    AliDielectronPID *pid=new AliDielectronPID("pid1","pid1");
    pid->SetDefaults(1);
    die->GetTrackFilter().AddCuts(pid);
  }

  //PID 6
  if (cutDefinition==2){
    AliDielectronPID *pid=new AliDielectronPID("pid6","pid6");
    pid->SetDefaults(6);
    die->GetTrackFilter().AddCuts(pid);
  }

  //PID 7
  if (cutDefinition==3){
    AliDielectronPID *pid=new AliDielectronPID("pid7","pid7");
    pid->SetDefaults(7);
    die->GetTrackFilter().AddCuts(pid);
  }

}

//______________________________________________________________________________________
void SetupPairCuts(AliDielectron *die, Int_t cutDefinition)
{
  //
  // Setup the pair cuts
  //

  // reject conversions
  // and select mass region
  AliDielectronVarCuts *openingAngleCut=new AliDielectronVarCuts("OpeningAngle","Opening angle > 35mrad");
  openingAngleCut->AddCut(AliDielectronVarManager::kOpeningAngle,.035,4.);
  openingAngleCut->AddCut(AliDielectronVarManager::kM,2.,4.);
  die->GetPairFilter().AddCuts(openingAngleCut);
}

//______________________________________________________________________________________
AliESDtrackCuts *SetupESDtrackCuts(Int_t cutDefinition)
{
  //
  // Setup default AliESDtrackCuts
  //
  AliESDtrackCuts *esdTrackCuts = new AliESDtrackCuts;

  esdTrackCuts->SetMaxDCAToVertexZ(3.0);
  esdTrackCuts->SetMaxDCAToVertexXY(.07);
  esdTrackCuts->SetRequireTPCRefit(kTRUE);
  esdTrackCuts->SetRequireITSRefit(kTRUE);
  esdTrackCuts->SetAcceptKinkDaughters(kFALSE);
  esdTrackCuts->SetClusterRequirementITS(AliESDtrackCuts::kSPD,AliESDtrackCuts::kFirst);

  esdTrackCuts->SetMinNClustersTPC(110);
  esdTrackCuts->SetMaxChi2PerClusterTPC(4);

  return esdTrackCuts;
}

//______________________________________________________________________________________
void InitHistograms(AliDielectron *die, Int_t cutDefinition)
{
  //
  // Initialise the QA histograms
  //

  //Setup QA histograms
  AliDielectronHistos *histos=
    new AliDielectronHistos(die->GetName(),
                            die->GetTitle());

  //Initialise histogram classes
  histos->SetReservedWords("Track;Pair");

  //Event class (only for last QA)
  if (cutDefinition==nDie-1) histos->AddClass("Event");

  //Track classes, only first event
  for (Int_t i=0; i<2; ++i){
    histos->AddClass(Form("Track_%s",AliDielectron::TrackClassName(i)));
  }

  //Pair classes, only first event
  for (Int_t i=0; i<3; ++i){
    histos->AddClass(Form("Pair_%s",AliDielectron::PairClassName(i)));
  }

  //Event histograms
  if (cutDefinition==nDie-1){
    //add histograms to event class
    histos->UserHistogram("Event","nEvents","Number of processed events after cuts;Number events",
                          1,0.,1.,AliDielectronVarManager::kNevents);
  }

  //add histograms to Track classes
  histos->UserHistogram("Track","Pt","Pt;Pt [GeV];#tracks",200,0,20.,AliDielectronVarManager::kPt);
  histos->UserHistogram("Track","dEdx_P","dEdx;P [GeV];TPC signal (arb units);#tracks",
                        400,0.2,20.,200,0.,200.,AliDielectronVarManager::kPIn,AliDielectronVarManager::kTPCsignal,kTRUE);
  histos->UserHistogram("Track","TPCnSigmaEle_P","TPC number of sigmas Electrons;P [GeV];TPC number of sigmas Electrons;#tracks",
                        400,0.2,20.,100,-5.,5.,AliDielectronVarManager::kPIn,AliDielectronVarManager::kTPCnSigmaEle,kTRUE);
  histos->UserHistogram("Track","TPCnSigmaPio_P","TPC number of sigmas Pions;P [GeV];TPC number of sigmas Pions;#tracks",
                        400,0.2,20.,100,-5.,5.,AliDielectronVarManager::kPIn,AliDielectronVarManager::kTPCnSigmaPio,kTRUE);
  histos->UserHistogram("Track","dXY","dXY;dXY [cm];#tracks",200,-2.,2.,AliDielectronVarManager::kImpactParXY);

  //add histograms to Pair classes
  histos->UserHistogram("Pair","InvMass","Inv.Mass;Inv. Mass [GeV];#pairs",
                        500,0.,4.,AliDielectronVarManager::kM);
  histos->UserHistogram("Pair","Rapidity","Rapidity;Rapidity;#pairs",
                        100,-2.,2.,AliDielectronVarManager::kY);
  histos->UserHistogram("Pair","OpeningAngle","Opening angle;angle",
                        100,0.,3.15,AliDielectronVarManager::kOpeningAngle);
  histos->UserHistogram("Pair","Chi2/NDF","#Chi^{2}/NDF;#Chi^{2}/NDF",
                        100, 0., 20., AliDielectronVarManager::kChi2NDF);

  die->SetHistogramManager(histos);
}

void InitCF(AliDielectron* die, Int_t cutDefinition)
{
  //
  // Setupd the CF Manager if needed
  //
  AliDielectronCF *cf=new AliDielectronCF(die->GetName(),die->GetTitle());

  //pair variables
  cf->AddVariable(AliDielectronVarManager::kPt,20,0,10);
  cf->AddVariable(AliDielectronVarManager::kY,40,-2,2);
  cf->AddVariable(AliDielectronVarManager::kM,200,-0.01,3.99);
  cf->AddVariable(AliDielectronVarManager::kPairType,10,0,10);
  //leg variables
  cf->AddVariable(AliDielectronVarManager::kPt,20,0,10,kTRUE);

  //only in this case write MC truth info
  cf->SetStepsForCutsIncreasing();
  if (cutDefinition==0){
    cf->SetStepForMCtruth();
  }

  die->SetCFManagerPair(cf);
}
<|endoftext|>


<commit_before>//#include <pch.h>
#include "DebugInput.h"

#include <Core/Engine.h>
#include <Core/InputSystem.h>
#include <GPU/Shader.h>

#include <Manager/AudioManager.h>
#include <Manager/DebugInfo.h>
#include <Manager/EventSystem.h>
#include <Manager/Manager.h>
#include <Manager/RenderingSystem.h>
#include <Manager/SceneManager.h>
#include <Manager/ShaderManager.h>

#include <UI/MenuSystem.h>

DebugInput::DebugInput()
	: ObjectInput(InputGroup::IG_DEBUG)
{
	SubscribeToEvent("ssao");
	SubscribeToEvent("forward-rendering");
}

void DebugInput::OnKeyPress(int key, int mods) {
	if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT)) {
		switch (key)
		{
			case GLFW_KEY_C:
				Manager::Event->EmitSync(EventType::SWITCH_CAMERA, nullptr);
				return;

			case GLFW_KEY_B:
				Manager::Event->EmitSync(EventType::DEBUG_BARREL_SPAWN, nullptr);
				return;

			case GLFW_KEY_I:
				printf("\n\nActive objects: %d\n\n", Manager::Scene->activeObjects.size());
				return;

			case GLFW_KEY_V:
				Manager::Debug->debugView = !Manager::Debug->debugView;
				return;
		}

		{
			int val = key - GLFW_KEY_F1;
			if (val >= 0 && val < 12) {
				Manager::RenderSys->debugParam = val + 1;
				return;
			}
		}

		if (key == GLFW_KEY_S) {
			Manager::RenderSys->Toggle(RenderState::SS_AO);
			return;
		}
	}

	switch (key)
	{
	case GLFW_KEY_P: {
		Engine::Pause();
		return;
	}

	case GLFW_KEY_F1: {
		Manager::RenderSys->Toggle(RenderState::DEBUG);
		return;
	}

	case GLFW_KEY_F3: {
		Manager::RenderSys->Toggle(RenderState::WIREFRAME);
		return;
	}

	case GLFW_KEY_F4: {
		Manager::RenderSys->Toggle(RenderState::POST_PROCESS);
		return;
	}

	case GLFW_KEY_F5: {
		Manager::Shader->Reload();
		return;
	}
	}
}

void DebugInput::OnEvent(const char *eventID, Object *data) {
	if (strcmp(eventID, "ssao") == 0) {
		ToggleEntry *entry = (ToggleEntry*) data;
		Manager::RenderSys->Set(RenderState::SS_AO, entry->GetState());
	}
	if (strcmp(eventID, "forward-rendering") == 0) {
		ToggleEntry *entry = (ToggleEntry*) data;
		Manager::RenderSys->Set(RenderState::POST_PROCESS, entry->GetState());
	}
}<commit_msg>removed unused event<commit_after>//#include <pch.h>
#include "DebugInput.h"

#include <Core/Engine.h>
#include <Core/InputSystem.h>
#include <GPU/Shader.h>

#include <Manager/AudioManager.h>
#include <Manager/DebugInfo.h>
#include <Manager/EventSystem.h>
#include <Manager/Manager.h>
#include <Manager/RenderingSystem.h>
#include <Manager/SceneManager.h>
#include <Manager/ShaderManager.h>

#include <UI/MenuSystem.h>

DebugInput::DebugInput()
	: ObjectInput(InputGroup::IG_DEBUG)
{
	SubscribeToEvent("ssao");
	SubscribeToEvent("forward-rendering");
}

void DebugInput::OnKeyPress(int key, int mods) {
	if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT)) {
		switch (key)
		{
			case GLFW_KEY_C:
				Manager::Event->EmitSync(EventType::SWITCH_CAMERA, nullptr);
				return;

			case GLFW_KEY_I:
				printf("\n\nActive objects: %d\n\n", Manager::Scene->activeObjects.size());
				return;

			case GLFW_KEY_V:
				Manager::Debug->debugView = !Manager::Debug->debugView;
				return;
		}

		{
			int val = key - GLFW_KEY_F1;
			if (val >= 0 && val < 12) {
				Manager::RenderSys->debugParam = val + 1;
				return;
			}
		}

		if (key == GLFW_KEY_S) {
			Manager::RenderSys->Toggle(RenderState::SS_AO);
			return;
		}
	}

	switch (key)
	{
	case GLFW_KEY_P: {
		Engine::Pause();
		return;
	}

	case GLFW_KEY_F1: {
		Manager::RenderSys->Toggle(RenderState::DEBUG);
		return;
	}

	case GLFW_KEY_F3: {
		Manager::RenderSys->Toggle(RenderState::WIREFRAME);
		return;
	}

	case GLFW_KEY_F4: {
		Manager::RenderSys->Toggle(RenderState::POST_PROCESS);
		return;
	}

	case GLFW_KEY_F5: {
		Manager::Shader->Reload();
		return;
	}
	}
}

void DebugInput::OnEvent(const char *eventID, Object *data) {
	if (strcmp(eventID, "ssao") == 0) {
		ToggleEntry *entry = (ToggleEntry*) data;
		Manager::RenderSys->Set(RenderState::SS_AO, entry->GetState());
	}
	if (strcmp(eventID, "forward-rendering") == 0) {
		ToggleEntry *entry = (ToggleEntry*) data;
		Manager::RenderSys->Set(RenderState::POST_PROCESS, entry->GetState());
	}
}<|endoftext|>


<commit_before>/*
	This file is part of the E_MinSG library.
	Copyright (C) 2007-2012 Benjamin Eikel <benjamin@eikel.org>
	Copyright (C) 2007-2012 Claudius Jähn <claudius@uni-paderborn.de>
	Copyright (C) 2007-2012 Ralf Petring <ralf@petring.net>

	This library is subject to the terms of the Mozilla Public License, v. 2.0.
	You should have received a copy of the MPL along with this library; see the
	file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "E_StdNodeVisitors.h"

// --
#include <MinSG/Helper/StdNodeVisitors.h>

#include "../ELibMinSG.h"

#include "../Core/Nodes/E_Node.h"
#include "../Core/Nodes/E_GroupNode.h"
#include "../Core/Nodes/E_ListNode.h"
#include "../Core/Nodes/E_GeometryNode.h"
#include "../Core/Nodes/E_LightNode.h"
#include "../Core/Nodes/E_CameraNode.h"
#include "../Core/States/E_State.h"
#include "../Core/E_FrameContext.h"

#include <EScript/Basics.h>
#include <EScript/StdObjects.h>

#include <E_Geometry/E_Matrix4x4.h>
#include <E_Geometry/E_Vec3.h>
#include <E_Geometry/E_Box.h>
#include <E_Geometry/E_Frustum.h>

using namespace EScript;
using namespace MinSG;
using namespace E_Geometry;

namespace E_MinSG {

//! init classes and Members
void init_stdNodeVisitors(EScript::Namespace * lib) {

	//! [ESF] Array collectClosedNodes(root)
	ES_FUNCTION(lib, "collectClosedNodes", 1, 1, {
		const auto nodes = collectClosedNodes((parameter[0].to<MinSG::Node*>(rt)));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectClosedNodesAtPosition(root,position)
	ES_FUNCTION(lib, "collectClosedNodesAtPosition", 2, 2, {
		const auto nodes = collectClosedNodesAtPosition((parameter[0].to<MinSG::Node*>(rt)),
														parameter[1].to<Geometry::Vec3>(rt));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectClosedNodesIntersectingBox(root,box)
	ES_FUNCTION(lib, "collectClosedNodesIntersectingBox", 2, 2, {
		const auto nodes = collectClosedNodesIntersectingBox((parameter[0].to<MinSG::Node*>(rt)),
															 parameter[1].to<const Geometry::Box&>(rt));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectGeoNodes(root)
	ES_FUNCTION(lib, "collectGeoNodes", 1, 1, {
		const auto nodes = collectNodes<GeometryNode>((parameter[0].to<MinSG::Node*>(rt)));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectGeoNodesAtPosition(root,position)
	ES_FUNCTION(lib, "collectGeoNodesAtPosition", 2, 2, {
		const auto nodes = collectGeoNodesAtPosition((parameter[0].to<MinSG::Node*>(rt)),
													 parameter[1].to<Geometry::Vec3>(rt));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectGeoNodesInFrustum(root,frustum, [bool includeIntersectingNodes])
	ES_FUNCTION(lib, "collectGeoNodesInFrustum", 2, 3, {
           const auto nodes = collectNodesInFrustum<GeometryNode>((parameter[0].to<MinSG::Node*>(rt)),
                                    parameter[1].to<const Geometry::Frustum&>(rt),parameter[2].toBool(true));
            return getENodeArray(nodes.begin(), nodes.end());

	})

	//! [ESF] Array collectGeoNodesIntersectingBox(root,box)
	ES_FUNCTION(lib, "collectGeoNodesIntersectingBox", 2, 2, {
		const auto nodes = collectGeoNodesIntersectingBox((parameter[0].to<MinSG::Node*>(rt)),
														  parameter[1].to<const Geometry::Box&>(rt));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectInstances(Node root,Node prototype)
	ES_FUNCTION(lib, "collectInstances", 2, 2, {
		const auto nodes = collectInstances(	(parameter[0].to<MinSG::Node*>(rt)),
												(parameter[1].to<MinSG::Node*>(rt)));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectLightNodes(root)
	ES_FUNCTION(lib, "collectLightNodes", 1, 1, {
		const auto nodes = collectNodes<LightNode>((parameter[0].to<MinSG::Node*>(rt)));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectNodes(root[, type])
	ES_FUNCTION(lib, "collectNodes", 1, 2, {
		const auto nodes = collectNodes<Node>((parameter[0].to<MinSG::Node*>(rt)));
		Type * nodeType = parameter.count() > 1 ? EScript::assertType<Type>(rt, parameter[1]) : nullptr;

		EScript::Array * nodeArray = EScript::Array::create();
		for(const auto & node : nodes) {
			ObjRef en = EScript::create(node);
			if(en.isNotNull() && (parameter.count() < 2 || en->isA(nodeType))) {
				nodeArray->pushBack(en);
			}
		}
		return nodeArray;
	})

	//! [ESF] Array collectNextNodesReferencingAttribute(root, attrName)
	ES_FUNCTION(lib, "collectNextNodesReferencingAttribute", 2, 2, {
		const auto nodes = collectNextNodesReferencingAttribute((parameter[0].to<MinSG::Node*>(rt)),parameter[1].toString());
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectNodesReferencingAttribute(root, attrName)
	ES_FUNCTION(lib, "collectNodesReferencingAttribute", 2, 2, {
		const auto nodes = collectNodesReferencingAttribute((parameter[0].to<MinSG::Node*>(rt)),parameter[1].toString());
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectNodesWithAttribute(root, attrName)
	ES_FUNCTION(lib, "collectNodesWithAttribute", 2, 2, {
		const auto nodes = collectNodesWithAttribute((parameter[0].to<MinSG::Node*>(rt)),parameter[1].toString());
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectVisibleNodes(root,FrameContext [[, Number or false maxDistance],bool fillDepthBuffer=false, Number renderingLayers])
	ES_FUNCTION(lib, "collectVisibleNodes", 2, 5, {
		const auto visNodes = collectVisibleNodes((parameter[0].to<MinSG::Node*>(rt)),
												parameter[1].to<MinSG::FrameContext&>(rt),
												parameter[2].toBool() ? parameter[2].toFloat() : -1.0,
												parameter[3].toBool(false),
												static_cast<renderingLayerMask_t>(parameter[4].toUInt(1)));
		return getENodeArray(visNodes.begin(),visNodes.end());
	})

	//! [ESF] Array collectStates(root[, type])
	ES_FUNCTION(lib, "collectStates", 1, 2, {
		const auto states = collectStates<State>((parameter[0].to<MinSG::Node*>(rt)));
		Type * stateType = parameter.count() > 1 ? EScript::assertType<Type>(rt, parameter[1]) : nullptr;

		EScript::Array * stateArray = EScript::Array::create();
		for(const auto & state : states) {
			ObjRef es = EScript::create(state);
			if(es.isNotNull() && (parameter.count() < 2 || es->isA(stateType))) {
				stateArray->pushBack(es);
			}
		}
		return stateArray;
	})

	//! [ESF] number countGeoNodes(root)
	ES_FUN(lib,"countGeoNodes",1,1,
			static_cast<uint32_t>(collectNodes<GeometryNode>((parameter[0].to<MinSG::Node*>(rt))).size()))

	//! [ESF] number countTriangles(root)
	ES_FUN(lib,"countTriangles",1,1,
				static_cast<uint32_t>(countTriangles(parameter[0].to<MinSG::Node*>(rt))))

	//! [ESF] number countTrianglesInFrustum(root, frustum)
	ES_FUN(lib,"countTrianglesInFrustum",2,2,
				static_cast<uint32_t>(countTrianglesInFrustum(
					parameter[0].to<MinSG::Node*>(rt),
					parameter[1].to<const Geometry::Frustum&>(rt)
				)))

	//! [ESF] number countGeoNodesInFrustum(root,camera)
	ES_FUNCTION(lib, "countGeoNodesInFrustum", 2, 2, {
		Node * root = parameter[0].to<MinSG::Node*>(rt);
		const CameraNode * camera = **EScript::assertType<E_CameraNode>(rt, parameter[1]);
		const Geometry::Frustum & frustum = camera->getFrustum();
		return static_cast<uint32_t>(collectNodesInFrustum<GeometryNode>(root, frustum).size());
	})

	//! [ESF] Array getChildNodes(root)
	ES_FUNCTION(lib, "getChildNodes", 1, 1, {
		const auto children = getChildNodes((parameter[0].to<MinSG::Node*>(rt)));
		return getENodeArray(children.begin(), children.end());
	})

	//! [ESF] Array countNodesInLevels(MinSG.Node)
	ES_FUNCTION(lib, "countNodesInLevels", 1, 1, {
		const auto levelCounts = countNodesInLevels(parameter[0].to<MinSG::Node*>(rt));

		Array * eLevelCounts = Array::create();
		eLevelCounts->reserve(levelCounts.size());
		for(const auto & levelCount : levelCounts) {
			eLevelCounts->pushBack(EScript::create(levelCount));
		}
		return eLevelCounts;
	})

	//! [ESF] void MinSG.moveTransformationsIntoClosedNodes(MinSG.Node)
	ES_FUN(lib, "moveTransformationsIntoClosedNodes", 1, 1, (
			MinSG::moveTransformationsIntoClosedNodes((parameter[0].to<MinSG::Node*>(rt))),
			EScript::create(nullptr)))

	//! [ESF] void MinSG.moveTransformationsIntoLeaves(MinSG.Node)
	ES_FUN(lib, "moveTransformationsIntoLeaves", 1, 1, (
				MinSG::moveTransformationsIntoLeaves((parameter[0].to<MinSG::Node*>(rt))),
				EScript::create(nullptr)))

	//! [ESF] void MinSG.moveStatesIntoClosedNodes(MinSG.Node)
	ES_FUN(lib, "moveStatesIntoClosedNodes", 1, 1, (
			MinSG::moveStatesIntoClosedNodes((parameter[0].to<MinSG::Node*>(rt))),
			EScript::create(nullptr)))

	//! [ESF] void MinSG.moveStatesIntoLeaves(MinSG.Node)
	ES_FUN(lib, "moveStatesIntoLeaves", 1, 1, (
				MinSG::moveStatesIntoLeaves((parameter[0].to<MinSG::Node*>(rt))),
				EScript::create(nullptr)))
}

}
<commit_msg>Bindings for new node visitor<commit_after>/*
	This file is part of the E_MinSG library.
	Copyright (C) 2007-2012 Benjamin Eikel <benjamin@eikel.org>
	Copyright (C) 2007-2012 Claudius Jähn <claudius@uni-paderborn.de>
	Copyright (C) 2007-2012 Ralf Petring <ralf@petring.net>

	This library is subject to the terms of the Mozilla Public License, v. 2.0.
	You should have received a copy of the MPL along with this library; see the
	file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "E_StdNodeVisitors.h"

// --
#include <MinSG/Helper/StdNodeVisitors.h>

#include "../ELibMinSG.h"

#include "../Core/Nodes/E_Node.h"
#include "../Core/Nodes/E_GroupNode.h"
#include "../Core/Nodes/E_ListNode.h"
#include "../Core/Nodes/E_GeometryNode.h"
#include "../Core/Nodes/E_LightNode.h"
#include "../Core/Nodes/E_CameraNode.h"
#include "../Core/States/E_State.h"
#include "../Core/E_FrameContext.h"

#include <EScript/Basics.h>
#include <EScript/StdObjects.h>

#include <E_Geometry/E_Matrix4x4.h>
#include <E_Geometry/E_Vec3.h>
#include <E_Geometry/E_Box.h>
#include <E_Geometry/E_Frustum.h>
#include <E_Geometry/E_Ray3.h>

using namespace EScript;
using namespace MinSG;
using namespace E_Geometry;

namespace E_MinSG {

//! init classes and Members
void init_stdNodeVisitors(EScript::Namespace * lib) {

	//! [ESF] Array collectClosedNodes(root)
	ES_FUNCTION(lib, "collectClosedNodes", 1, 1, {
		const auto nodes = collectClosedNodes((parameter[0].to<MinSG::Node*>(rt)));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectClosedNodesAtPosition(root,position)
	ES_FUNCTION(lib, "collectClosedNodesAtPosition", 2, 2, {
		const auto nodes = collectClosedNodesAtPosition((parameter[0].to<MinSG::Node*>(rt)),
														parameter[1].to<Geometry::Vec3>(rt));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectClosedNodesIntersectingBox(root,box)
	ES_FUNCTION(lib, "collectClosedNodesIntersectingBox", 2, 2, {
		const auto nodes = collectClosedNodesIntersectingBox((parameter[0].to<MinSG::Node*>(rt)),
															 parameter[1].to<const Geometry::Box&>(rt));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectGeoNodes(root)
	ES_FUNCTION(lib, "collectGeoNodes", 1, 1, {
		const auto nodes = collectNodes<GeometryNode>((parameter[0].to<MinSG::Node*>(rt)));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectGeoNodesAtPosition(root,position)
	ES_FUNCTION(lib, "collectGeoNodesAtPosition", 2, 2, {
		const auto nodes = collectGeoNodesAtPosition((parameter[0].to<MinSG::Node*>(rt)),
													 parameter[1].to<Geometry::Vec3>(rt));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectGeoNodesInFrustum(root,frustum, [bool includeIntersectingNodes])
	ES_FUNCTION(lib, "collectGeoNodesInFrustum", 2, 3, {
           const auto nodes = collectNodesInFrustum<GeometryNode>((parameter[0].to<MinSG::Node*>(rt)),
                                    parameter[1].to<const Geometry::Frustum&>(rt),parameter[2].toBool(true));
            return getENodeArray(nodes.begin(), nodes.end());

	})

	//! [ESF] Array collectGeoNodesIntersectingBox(root,box)
	ES_FUNCTION(lib, "collectGeoNodesIntersectingBox", 2, 2, {
		const auto nodes = collectGeoNodesIntersectingBox((parameter[0].to<MinSG::Node*>(rt)),
														  parameter[1].to<const Geometry::Box&>(rt));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectGeoNodesIntersectingBox(root,(pos,dir|ray))
	ES_FUNCTION(lib, "collectGeoNodesIntersectingRay", 2, 3, {
		Geometry::Ray3 ray;
		if(parameter.count() == 2) {
			ray = parameter[1].to<const Geometry::Ray3&>(rt);
		} else {
			ray.setOrigin(parameter[1].to<const Geometry::Vec3&>(rt));
			ray.setDirection(parameter[2].to<const Geometry::Vec3&>(rt));
		}
		const auto nodes = collectGeoNodesIntersectingRay((parameter[0].to<MinSG::Node*>(rt)),
														  ray.getOrigin(), ray.getDirection());
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectInstances(Node root,Node prototype)
	ES_FUNCTION(lib, "collectInstances", 2, 2, {
		const auto nodes = collectInstances(	(parameter[0].to<MinSG::Node*>(rt)),
												(parameter[1].to<MinSG::Node*>(rt)));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectLightNodes(root)
	ES_FUNCTION(lib, "collectLightNodes", 1, 1, {
		const auto nodes = collectNodes<LightNode>((parameter[0].to<MinSG::Node*>(rt)));
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectNodes(root[, type])
	ES_FUNCTION(lib, "collectNodes", 1, 2, {
		const auto nodes = collectNodes<Node>((parameter[0].to<MinSG::Node*>(rt)));
		Type * nodeType = parameter.count() > 1 ? EScript::assertType<Type>(rt, parameter[1]) : nullptr;

		EScript::Array * nodeArray = EScript::Array::create();
		for(const auto & node : nodes) {
			ObjRef en = EScript::create(node);
			if(en.isNotNull() && (parameter.count() < 2 || en->isA(nodeType))) {
				nodeArray->pushBack(en);
			}
		}
		return nodeArray;
	})

	//! [ESF] Array collectNextNodesReferencingAttribute(root, attrName)
	ES_FUNCTION(lib, "collectNextNodesReferencingAttribute", 2, 2, {
		const auto nodes = collectNextNodesReferencingAttribute((parameter[0].to<MinSG::Node*>(rt)),parameter[1].toString());
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectNodesReferencingAttribute(root, attrName)
	ES_FUNCTION(lib, "collectNodesReferencingAttribute", 2, 2, {
		const auto nodes = collectNodesReferencingAttribute((parameter[0].to<MinSG::Node*>(rt)),parameter[1].toString());
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectNodesWithAttribute(root, attrName)
	ES_FUNCTION(lib, "collectNodesWithAttribute", 2, 2, {
		const auto nodes = collectNodesWithAttribute((parameter[0].to<MinSG::Node*>(rt)),parameter[1].toString());
		return getENodeArray(nodes.begin(), nodes.end());
	})

	//! [ESF] Array collectVisibleNodes(root,FrameContext [[, Number or false maxDistance],bool fillDepthBuffer=false, Number renderingLayers])
	ES_FUNCTION(lib, "collectVisibleNodes", 2, 5, {
		const auto visNodes = collectVisibleNodes((parameter[0].to<MinSG::Node*>(rt)),
												parameter[1].to<MinSG::FrameContext&>(rt),
												parameter[2].toBool() ? parameter[2].toFloat() : -1.0,
												parameter[3].toBool(false),
												static_cast<renderingLayerMask_t>(parameter[4].toUInt(1)));
		return getENodeArray(visNodes.begin(),visNodes.end());
	})

	//! [ESF] Array collectStates(root[, type])
	ES_FUNCTION(lib, "collectStates", 1, 2, {
		const auto states = collectStates<State>((parameter[0].to<MinSG::Node*>(rt)));
		Type * stateType = parameter.count() > 1 ? EScript::assertType<Type>(rt, parameter[1]) : nullptr;

		EScript::Array * stateArray = EScript::Array::create();
		for(const auto & state : states) {
			ObjRef es = EScript::create(state);
			if(es.isNotNull() && (parameter.count() < 2 || es->isA(stateType))) {
				stateArray->pushBack(es);
			}
		}
		return stateArray;
	})

	//! [ESF] number countGeoNodes(root)
	ES_FUN(lib,"countGeoNodes",1,1,
			static_cast<uint32_t>(collectNodes<GeometryNode>((parameter[0].to<MinSG::Node*>(rt))).size()))

	//! [ESF] number countTriangles(root)
	ES_FUN(lib,"countTriangles",1,1,
				static_cast<uint32_t>(countTriangles(parameter[0].to<MinSG::Node*>(rt))))

	//! [ESF] number countTrianglesInFrustum(root, frustum)
	ES_FUN(lib,"countTrianglesInFrustum",2,2,
				static_cast<uint32_t>(countTrianglesInFrustum(
					parameter[0].to<MinSG::Node*>(rt),
					parameter[1].to<const Geometry::Frustum&>(rt)
				)))

	//! [ESF] number countGeoNodesInFrustum(root,camera)
	ES_FUNCTION(lib, "countGeoNodesInFrustum", 2, 2, {
		Node * root = parameter[0].to<MinSG::Node*>(rt);
		const CameraNode * camera = **EScript::assertType<E_CameraNode>(rt, parameter[1]);
		const Geometry::Frustum & frustum = camera->getFrustum();
		return static_cast<uint32_t>(collectNodesInFrustum<GeometryNode>(root, frustum).size());
	})

	//! [ESF] Array getChildNodes(root)
	ES_FUNCTION(lib, "getChildNodes", 1, 1, {
		const auto children = getChildNodes((parameter[0].to<MinSG::Node*>(rt)));
		return getENodeArray(children.begin(), children.end());
	})

	//! [ESF] Array countNodesInLevels(MinSG.Node)
	ES_FUNCTION(lib, "countNodesInLevels", 1, 1, {
		const auto levelCounts = countNodesInLevels(parameter[0].to<MinSG::Node*>(rt));

		Array * eLevelCounts = Array::create();
		eLevelCounts->reserve(levelCounts.size());
		for(const auto & levelCount : levelCounts) {
			eLevelCounts->pushBack(EScript::create(levelCount));
		}
		return eLevelCounts;
	})

	//! [ESF] void MinSG.moveTransformationsIntoClosedNodes(MinSG.Node)
	ES_FUN(lib, "moveTransformationsIntoClosedNodes", 1, 1, (
			MinSG::moveTransformationsIntoClosedNodes((parameter[0].to<MinSG::Node*>(rt))),
			EScript::create(nullptr)))

	//! [ESF] void MinSG.moveTransformationsIntoLeaves(MinSG.Node)
	ES_FUN(lib, "moveTransformationsIntoLeaves", 1, 1, (
				MinSG::moveTransformationsIntoLeaves((parameter[0].to<MinSG::Node*>(rt))),
				EScript::create(nullptr)))

	//! [ESF] void MinSG.moveStatesIntoClosedNodes(MinSG.Node)
	ES_FUN(lib, "moveStatesIntoClosedNodes", 1, 1, (
			MinSG::moveStatesIntoClosedNodes((parameter[0].to<MinSG::Node*>(rt))),
			EScript::create(nullptr)))

	//! [ESF] void MinSG.moveStatesIntoLeaves(MinSG.Node)
	ES_FUN(lib, "moveStatesIntoLeaves", 1, 1, (
				MinSG::moveStatesIntoLeaves((parameter[0].to<MinSG::Node*>(rt))),
				EScript::create(nullptr)))
}

}
<|endoftext|>