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

// Tests for the Command Buffer Helper.

#include "base/at_exit.h"
#include "base/callback.h"
#include "base/message_loop.h"
#include "base/scoped_nsautorelease_pool.h"
#include "gpu/command_buffer/client/cmd_buffer_helper.h"
#include "gpu/command_buffer/service/mocks.h"
#include "gpu/command_buffer/service/command_buffer_service.h"
#include "gpu/command_buffer/service/gpu_processor.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace gpu {

using testing::Return;
using testing::Mock;
using testing::Truly;
using testing::Sequence;
using testing::DoAll;
using testing::Invoke;
using testing::_;

const int32 kNumCommandEntries = 10;
const int32 kCommandBufferSizeBytes =
    kNumCommandEntries * sizeof(CommandBufferEntry);

// Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper,
// using a CommandBufferEngine with a mock AsyncAPIInterface for its interface
// (calling it directly, not through the RPC mechanism).
class CommandBufferHelperTest : public testing::Test {
 protected:
  virtual void SetUp() {
    api_mock_.reset(new AsyncAPIMock);
    // ignore noops in the mock - we don't want to inspect the internals of the
    // helper.
    EXPECT_CALL(*api_mock_, DoCommand(0, _, _))
        .WillRepeatedly(Return(error::kNoError));

    command_buffer_.reset(new CommandBufferService);
    command_buffer_->Initialize(kNumCommandEntries);
    Buffer ring_buffer = command_buffer_->GetRingBuffer();

    parser_ = new CommandParser(ring_buffer.ptr,
                                ring_buffer.size,
                                0,
                                ring_buffer.size,
                                0,
                                api_mock_.get());

    scoped_refptr<GPUProcessor> gpu_processor(new GPUProcessor(
        command_buffer_.get(), NULL, parser_, 1));
    command_buffer_->SetPutOffsetChangeCallback(NewCallback(
        gpu_processor.get(), &GPUProcessor::ProcessCommands));

    api_mock_->set_engine(gpu_processor.get());

    helper_.reset(new CommandBufferHelper(command_buffer_.get()));
    helper_->Initialize();
  }

  virtual void TearDown() {
    // If the GPUProcessor posts any tasks, this forces them to run.
    MessageLoop::current()->RunAllPending();
    helper_.release();
  }

  // Adds a command to the buffer through the helper, while adding it as an
  // expected call on the API mock.
  void AddCommandWithExpect(error::Error _return,
                            unsigned int command,
                            int arg_count,
                            CommandBufferEntry *args) {
    CommandHeader header;
    header.size = arg_count + 1;
    header.command = command;
    CommandBufferEntry* cmds = helper_->GetSpace(arg_count + 1);
    CommandBufferOffset put = 0;
    cmds[put++].value_header = header;
    for (int ii = 0; ii < arg_count; ++ii) {
      cmds[put++] = args[ii];
    }

    EXPECT_CALL(*api_mock_, DoCommand(command, arg_count,
        Truly(AsyncAPIMock::IsArgs(arg_count, args))))
        .InSequence(sequence_)
        .WillOnce(Return(_return));
  }

  // Checks that the buffer from put to put+size is free in the parser.
  void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
    CommandBufferOffset parser_put = parser_->put();
    CommandBufferOffset parser_get = parser_->get();
    CommandBufferOffset limit = put + size;
    if (parser_get > parser_put) {
      // "busy" buffer wraps, so "free" buffer is between put (inclusive) and
      // get (exclusive).
      EXPECT_LE(parser_put, put);
      EXPECT_GT(parser_get, limit);
    } else {
      // "busy" buffer does not wrap, so the "free" buffer is the top side (from
      // put to the limit) and the bottom side (from 0 to get).
      if (put >= parser_put) {
        // we're on the top side, check we are below the limit.
        EXPECT_GE(kNumCommandEntries, limit);
      } else {
        // we're on the bottom side, check we are below get.
        EXPECT_GT(parser_get, limit);
      }
    }
  }

  int32 GetGetOffset() {
    return command_buffer_->GetState().get_offset;
  }

  int32 GetPutOffset() {
    return command_buffer_->GetState().put_offset;
  }

  error::Error GetError() {
    return command_buffer_->GetState().error;
  }

  CommandBufferOffset get_helper_put() { return helper_->put_; }

  base::ScopedNSAutoreleasePool autorelease_pool_;
  base::AtExitManager at_exit_manager_;
  MessageLoop message_loop_;
  scoped_ptr<AsyncAPIMock> api_mock_;
  scoped_ptr<CommandBufferService> command_buffer_;
  CommandParser* parser_;
  scoped_ptr<CommandBufferHelper> helper_;
  Sequence sequence_;
};

// Checks that commands in the buffer are properly executed, and that the
// status/error stay valid.
TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
  // Check initial state of the engine - it should have been configured by the
  // helper.
  EXPECT_TRUE(parser_ != NULL);
  EXPECT_EQ(error::kNoError, GetError());
  EXPECT_EQ(0, GetGetOffset());

  // Add 3 commands through the helper
  AddCommandWithExpect(error::kNoError, 1, 0, NULL);

  CommandBufferEntry args1[2];
  args1[0].value_uint32 = 3;
  args1[1].value_float = 4.f;
  AddCommandWithExpect(error::kNoError, 2, 2, args1);

  CommandBufferEntry args2[2];
  args2[0].value_uint32 = 5;
  args2[1].value_float = 6.f;
  AddCommandWithExpect(error::kNoError, 3, 2, args2);

  helper_->Flush();
  // Check that the engine has work to do now.
  EXPECT_FALSE(parser_->IsEmpty());

  // Wait until it's done.
  helper_->Finish();
  // Check that the engine has no more work to do.
  EXPECT_TRUE(parser_->IsEmpty());

  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

// Checks that commands in the buffer are properly executed when wrapping the
// buffer, and that the status/error stay valid.
TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
  // Add 5 commands of size 3 through the helper to make sure we do wrap.
  CommandBufferEntry args1[2];
  args1[0].value_uint32 = 3;
  args1[1].value_float = 4.f;

  for (unsigned int i = 0; i < 5; ++i) {
    AddCommandWithExpect(error::kNoError, i + 1, 2, args1);
  }

  helper_->Finish();
  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

// Checks that asking for available entries work, and that the parser
// effectively won't use that space.
TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
  CommandBufferEntry args[2];
  args[0].value_uint32 = 3;
  args[1].value_float = 4.f;

  // Add 2 commands through the helper - 8 entries
  AddCommandWithExpect(error::kNoError, 1, 0, NULL);
  AddCommandWithExpect(error::kNoError, 2, 0, NULL);
  AddCommandWithExpect(error::kNoError, 3, 2, args);
  AddCommandWithExpect(error::kNoError, 4, 2, args);

  // Ask for 5 entries.
  helper_->WaitForAvailableEntries(5);

  CommandBufferOffset put = get_helper_put();
  CheckFreeSpace(put, 5);

  // Add more commands.
  AddCommandWithExpect(error::kNoError, 5, 2, args);

  // Wait until everything is done done.
  helper_->Finish();

  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

// Checks that the InsertToken/WaitForToken work.
TEST_F(CommandBufferHelperTest, TestToken) {
  CommandBufferEntry args[2];
  args[0].value_uint32 = 3;
  args[1].value_float = 4.f;

  // Add a first command.
  AddCommandWithExpect(error::kNoError, 3, 2, args);
  // keep track of the buffer position.
  CommandBufferOffset command1_put = get_helper_put();
  int32 token = helper_->InsertToken();

  EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
      .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
                      Return(error::kNoError)));
  // Add another command.
  AddCommandWithExpect(error::kNoError, 4, 2, args);
  helper_->WaitForToken(token);
  // check that the get pointer is beyond the first command.
  EXPECT_LE(command1_put, GetGetOffset());
  helper_->Finish();

  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

}  // namespace gpu
<commit_msg>Add command buffer test for case where command inserted exactly matches the space left in the command buffer.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Tests for the Command Buffer Helper.

#include "base/at_exit.h"
#include "base/callback.h"
#include "base/message_loop.h"
#include "base/scoped_nsautorelease_pool.h"
#include "gpu/command_buffer/client/cmd_buffer_helper.h"
#include "gpu/command_buffer/service/mocks.h"
#include "gpu/command_buffer/service/command_buffer_service.h"
#include "gpu/command_buffer/service/gpu_processor.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace gpu {

using testing::Return;
using testing::Mock;
using testing::Truly;
using testing::Sequence;
using testing::DoAll;
using testing::Invoke;
using testing::_;

const int32 kNumCommandEntries = 10;
const int32 kCommandBufferSizeBytes =
    kNumCommandEntries * sizeof(CommandBufferEntry);

// Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper,
// using a CommandBufferEngine with a mock AsyncAPIInterface for its interface
// (calling it directly, not through the RPC mechanism).
class CommandBufferHelperTest : public testing::Test {
 protected:
  virtual void SetUp() {
    api_mock_.reset(new AsyncAPIMock);
    // ignore noops in the mock - we don't want to inspect the internals of the
    // helper.
    EXPECT_CALL(*api_mock_, DoCommand(0, _, _))
        .WillRepeatedly(Return(error::kNoError));

    command_buffer_.reset(new CommandBufferService);
    command_buffer_->Initialize(kNumCommandEntries);
    Buffer ring_buffer = command_buffer_->GetRingBuffer();

    parser_ = new CommandParser(ring_buffer.ptr,
                                ring_buffer.size,
                                0,
                                ring_buffer.size,
                                0,
                                api_mock_.get());

    scoped_refptr<GPUProcessor> gpu_processor(new GPUProcessor(
        command_buffer_.get(), NULL, parser_, 1));
    command_buffer_->SetPutOffsetChangeCallback(NewCallback(
        gpu_processor.get(), &GPUProcessor::ProcessCommands));

    api_mock_->set_engine(gpu_processor.get());

    helper_.reset(new CommandBufferHelper(command_buffer_.get()));
    helper_->Initialize();
  }

  virtual void TearDown() {
    // If the GPUProcessor posts any tasks, this forces them to run.
    MessageLoop::current()->RunAllPending();
    helper_.release();
  }

  // Adds a command to the buffer through the helper, while adding it as an
  // expected call on the API mock.
  void AddCommandWithExpect(error::Error _return,
                            unsigned int command,
                            int arg_count,
                            CommandBufferEntry *args) {
    CommandHeader header;
    header.size = arg_count + 1;
    header.command = command;
    CommandBufferEntry* cmds = helper_->GetSpace(arg_count + 1);
    CommandBufferOffset put = 0;
    cmds[put++].value_header = header;
    for (int ii = 0; ii < arg_count; ++ii) {
      cmds[put++] = args[ii];
    }

    EXPECT_CALL(*api_mock_, DoCommand(command, arg_count,
        Truly(AsyncAPIMock::IsArgs(arg_count, args))))
        .InSequence(sequence_)
        .WillOnce(Return(_return));
  }

  // Checks that the buffer from put to put+size is free in the parser.
  void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
    CommandBufferOffset parser_put = parser_->put();
    CommandBufferOffset parser_get = parser_->get();
    CommandBufferOffset limit = put + size;
    if (parser_get > parser_put) {
      // "busy" buffer wraps, so "free" buffer is between put (inclusive) and
      // get (exclusive).
      EXPECT_LE(parser_put, put);
      EXPECT_GT(parser_get, limit);
    } else {
      // "busy" buffer does not wrap, so the "free" buffer is the top side (from
      // put to the limit) and the bottom side (from 0 to get).
      if (put >= parser_put) {
        // we're on the top side, check we are below the limit.
        EXPECT_GE(kNumCommandEntries, limit);
      } else {
        // we're on the bottom side, check we are below get.
        EXPECT_GT(parser_get, limit);
      }
    }
  }

  int32 GetGetOffset() {
    return command_buffer_->GetState().get_offset;
  }

  int32 GetPutOffset() {
    return command_buffer_->GetState().put_offset;
  }

  error::Error GetError() {
    return command_buffer_->GetState().error;
  }

  CommandBufferOffset get_helper_put() { return helper_->put_; }

  base::ScopedNSAutoreleasePool autorelease_pool_;
  base::AtExitManager at_exit_manager_;
  MessageLoop message_loop_;
  scoped_ptr<AsyncAPIMock> api_mock_;
  scoped_ptr<CommandBufferService> command_buffer_;
  CommandParser* parser_;
  scoped_ptr<CommandBufferHelper> helper_;
  Sequence sequence_;
};

// Checks that commands in the buffer are properly executed, and that the
// status/error stay valid.
TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
  // Check initial state of the engine - it should have been configured by the
  // helper.
  EXPECT_TRUE(parser_ != NULL);
  EXPECT_EQ(error::kNoError, GetError());
  EXPECT_EQ(0, GetGetOffset());

  // Add 3 commands through the helper
  AddCommandWithExpect(error::kNoError, 1, 0, NULL);

  CommandBufferEntry args1[2];
  args1[0].value_uint32 = 3;
  args1[1].value_float = 4.f;
  AddCommandWithExpect(error::kNoError, 2, 2, args1);

  CommandBufferEntry args2[2];
  args2[0].value_uint32 = 5;
  args2[1].value_float = 6.f;
  AddCommandWithExpect(error::kNoError, 3, 2, args2);

  helper_->Flush();
  // Check that the engine has work to do now.
  EXPECT_FALSE(parser_->IsEmpty());

  // Wait until it's done.
  helper_->Finish();
  // Check that the engine has no more work to do.
  EXPECT_TRUE(parser_->IsEmpty());

  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

// Checks that commands in the buffer are properly executed when wrapping the
// buffer, and that the status/error stay valid.
TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
  // Add 5 commands of size 3 through the helper to make sure we do wrap.
  CommandBufferEntry args1[2];
  args1[0].value_uint32 = 5;
  args1[1].value_float = 4.f;

  for (unsigned int i = 0; i < 5; ++i) {
    AddCommandWithExpect(error::kNoError, i + 1, 2, args1);
  }

  helper_->Finish();
  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

// Checks the case where the command inserted exactly matches the space left in
// the command buffer.
TEST_F(CommandBufferHelperTest, TestCommandWrappingExactMultiple) {
  const int32 kCommandSize = 5;
  const int32 kNumArgs = kCommandSize - 1;
  COMPILE_ASSERT(kNumCommandEntries % kCommandSize == 0,
                 Not_multiple_of_num_command_entries);
  CommandBufferEntry args1[kNumArgs];
  for (size_t ii = 0; ii < kNumArgs; ++ii) {
    args1[0].value_uint32 = ii + 1;
  }

  for (unsigned int i = 0; i < 5; ++i) {
    AddCommandWithExpect(error::kNoError, i + 1, kNumArgs, args1);
  }

  helper_->Finish();
  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

// Checks that asking for available entries work, and that the parser
// effectively won't use that space.
TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
  CommandBufferEntry args[2];
  args[0].value_uint32 = 3;
  args[1].value_float = 4.f;

  // Add 2 commands through the helper - 8 entries
  AddCommandWithExpect(error::kNoError, 1, 0, NULL);
  AddCommandWithExpect(error::kNoError, 2, 0, NULL);
  AddCommandWithExpect(error::kNoError, 3, 2, args);
  AddCommandWithExpect(error::kNoError, 4, 2, args);

  // Ask for 5 entries.
  helper_->WaitForAvailableEntries(5);

  CommandBufferOffset put = get_helper_put();
  CheckFreeSpace(put, 5);

  // Add more commands.
  AddCommandWithExpect(error::kNoError, 5, 2, args);

  // Wait until everything is done done.
  helper_->Finish();

  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

// Checks that the InsertToken/WaitForToken work.
TEST_F(CommandBufferHelperTest, TestToken) {
  CommandBufferEntry args[2];
  args[0].value_uint32 = 3;
  args[1].value_float = 4.f;

  // Add a first command.
  AddCommandWithExpect(error::kNoError, 3, 2, args);
  // keep track of the buffer position.
  CommandBufferOffset command1_put = get_helper_put();
  int32 token = helper_->InsertToken();

  EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
      .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
                      Return(error::kNoError)));
  // Add another command.
  AddCommandWithExpect(error::kNoError, 4, 2, args);
  helper_->WaitForToken(token);
  // check that the get pointer is beyond the first command.
  EXPECT_LE(command1_put, GetGetOffset());
  helper_->Finish();

  // Check that the commands did happen.
  Mock::VerifyAndClearExpectations(api_mock_.get());

  // Check the error status.
  EXPECT_EQ(error::kNoError, GetError());
}

}  // namespace gpu
<|endoftext|>


<commit_before>#include "KeyValBase.h"

#include <iostream>
#include <array>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>

#include "utils.h"

size_t KeyValBase::depth() const
{
	return depth_;
}

void KeyValBase::depth(size_t depth) const
{
	depth_ = depth;
}

std::string KeyValBase::operator[](const std::string& key) const
{
	if (keyvals.count(key) == 0) return "";
	return keyvals.at(key);
}

std::string& KeyValBase::operator[](const std::string& key)
{
	return keyvals[key];
}

std::string KeyValBase::get(const std::string& key) const
{
	return (*this)[key];
}

std::pair<std::string, std::string> KeyValBase::parseKeyval(std::string_view keyval)
{
	namespace qi = boost::spirit::qi;
	namespace ascii = boost::spirit::ascii;

	auto trimmed = trim(keyval);

	//auto fsplit = trimmed.find_first_of("\"", 1);
	//if (fsplit > trimmed.length())
	//	fsplit = trimmed.length();

	//auto left = trimmed.substr(0, fsplit);
	//left = trim(left, "\"");

	//if (fsplit == trimmed.length())
	//	return std::make_pair("", "");

	//auto esplit = trimmed.find_first_of("\"", fsplit + 1);
	//if (esplit == 0 || esplit >= trimmed.length())
	//	esplit = fsplit;

	//auto right = trimmed.substr(esplit + 1);
	//right = trim(right, "\"");

	//std::string key{ right }, value{ left };

	std::pair<std::string, std::string> ret;

	if (!qi::parse(trimmed.cbegin(), trimmed.cend(), '"' >> +(qi::char_ - '"') >> '"' >> ' ' >> '"' >> +(qi::char_ - '"') >> '"', ret))
		throw std::exception("Failed to parse keyval");

	return ret;
}

std::string KeyValBase::toStr(const std::pair<std::string, std::string>& pair, char enclose)
{
	return enclose + pair.first + enclose + ' ' + enclose + pair.second + enclose;
}

size_t KeyValBase::parse(std::istream& stream)
{
	size_t numparsed = 0;
	std::string curline;

	while (trim(curline) != "{")
	{
		getline(stream, curline);
		numparsed++;
	}
	unsigned int depth = 1;

	while (getline(stream, curline))
	{
		numparsed++;

		auto trimmedCurline = trim(curline);

		if (trimmedCurline == "}")
		{
			if (--depth == 0)
				break;
		}
		else if (trimmedCurline == "{")
		{
			++depth;
		}
		else if (trimmedCurline.find_first_of('"') != std::string::npos)
		{
			auto [k, v] = parseKeyval(curline);
			keyvals[k] = v;
		}
		else
		{
			numparsed += parseSpecial(stream, trimmedCurline);
		}
	}
	if (auto it = keyvals.find("id"); it != keyvals.end())
	{
		this->id_ = atoi(it->second.c_str());
		keyvals.erase("id");
	}
	return numparsed;
}

size_t KeyValBase::parseSpecial(std::istream & stream, std::string_view type)
{
	return 0;
}

bool KeyValBase::empty() const
{
	return keyvals.empty();
}

void KeyValBase::extraOutput(std::ostream & os) const
{
}

KeyValBase::KeyValBase(std::initializer_list<decltype(keyvals)::value_type> init)
	: keyvals(init)
{
}
<commit_msg>Move value when inserting into keyvalues.<commit_after>#include "KeyValBase.h"

#include <iostream>
#include <array>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>

#include "utils.h"

size_t KeyValBase::depth() const
{
	return depth_;
}

void KeyValBase::depth(size_t depth) const
{
	depth_ = depth;
}

std::string KeyValBase::operator[](const std::string& key) const
{
	if (keyvals.count(key) == 0) return "";
	return keyvals.at(key);
}

std::string& KeyValBase::operator[](const std::string& key)
{
	return keyvals[key];
}

std::string KeyValBase::get(const std::string& key) const
{
	return (*this)[key];
}

std::pair<std::string, std::string> KeyValBase::parseKeyval(std::string_view keyval)
{
	namespace qi = boost::spirit::qi;
	namespace ascii = boost::spirit::ascii;

	auto trimmed = trim(keyval);

	//auto fsplit = trimmed.find_first_of("\"", 1);
	//if (fsplit > trimmed.length())
	//	fsplit = trimmed.length();

	//auto left = trimmed.substr(0, fsplit);
	//left = trim(left, "\"");

	//if (fsplit == trimmed.length())
	//	return std::make_pair("", "");

	//auto esplit = trimmed.find_first_of("\"", fsplit + 1);
	//if (esplit == 0 || esplit >= trimmed.length())
	//	esplit = fsplit;

	//auto right = trimmed.substr(esplit + 1);
	//right = trim(right, "\"");

	//std::string key{ right }, value{ left };

	std::pair<std::string, std::string> ret;

	if (!qi::parse(trimmed.cbegin(), trimmed.cend(), '"' >> +(qi::char_ - '"') >> '"' >> ' ' >> '"' >> +(qi::char_ - '"') >> '"', ret))
		throw std::exception("Failed to parse keyval");

	return ret;
}

std::string KeyValBase::toStr(const std::pair<std::string, std::string>& pair, char enclose)
{
	return enclose + pair.first + enclose + ' ' + enclose + pair.second + enclose;
}

size_t KeyValBase::parse(std::istream& stream)
{
	size_t numparsed = 0;
	std::string curline;

	while (trim(curline) != "{")
	{
		getline(stream, curline);
		numparsed++;
	}
	unsigned int depth = 1;

	while (getline(stream, curline))
	{
		numparsed++;

		auto trimmedCurline = trim(curline);

		if (trimmedCurline == "}")
		{
			if (--depth == 0)
				break;
		}
		else if (trimmedCurline == "{")
		{
			++depth;
		}
		else if (trimmedCurline.find_first_of('"') != std::string::npos)
		{
			auto [k, v] = parseKeyval(curline);
			keyvals[k] = std::move(v);
		}
		else
		{
			numparsed += parseSpecial(stream, trimmedCurline);
		}
	}
	if (auto it = keyvals.find("id"); it != keyvals.end())
	{
		this->id_ = atoi(it->second.c_str());
		keyvals.erase("id");
	}
	return numparsed;
}

size_t KeyValBase::parseSpecial(std::istream & stream, std::string_view type)
{
	return 0;
}

bool KeyValBase::empty() const
{
	return keyvals.empty();
}

void KeyValBase::extraOutput(std::ostream & os) const
{
}

KeyValBase::KeyValBase(std::initializer_list<decltype(keyvals)::value_type> init)
	: keyvals(init)
{
}
<|endoftext|>


<commit_before>#include "TileRenderer.h"
#include "components/Options.h"
#include "components/ThreadWorker.h"
#include "graphics/ViewState.h"
#include "projections/ProjectionSurface.h"
#include "projections/PlanarProjectionSurface.h"
#include "renderers/MapRenderer.h"
#include "renderers/drawdatas/TileDrawData.h"
#include "renderers/utils/GLResourceManager.h"
#include "renderers/utils/VTRenderer.h"
#include "utils/Log.h"

#include <vt/Label.h>
#include <vt/LabelCuller.h>
#include <vt/TileTransformer.h>
#include <vt/GLTileRenderer.h>
#include <vt/GLExtensions.h>

#include <cglib/mat.h>

namespace carto {

    TileRenderer::TileRenderer() :
        _mapRenderer(),
        _options(),
        _tileTransformer(),
        _vtRenderer(),
        _interactionMode(false),
        _subTileBlending(true),
        _labelOrder(0),
        _buildingOrder(1),
        _rasterFilterMode(vt::RasterFilterMode::BILINEAR),
        _horizontalLayerOffset(0),
        _viewDir(0, 0, 0),
        _mainLightDir(0, 0, 0),
        _tiles(),
        _mutex()
    {
    }

    TileRenderer::~TileRenderer() {
    }

    void TileRenderer::setComponents(const std::weak_ptr<Options>& options, const std::weak_ptr<MapRenderer>& mapRenderer) {
        std::lock_guard<std::mutex> lock(_mutex);
        _options = options;
        _mapRenderer = mapRenderer;
        _vtRenderer.reset();
    }

    std::shared_ptr<vt::TileTransformer> TileRenderer::getTileTransformer() const {
        std::lock_guard<std::mutex> lock(_mutex);
        return _tileTransformer;
    }

    void TileRenderer::setTileTransformer(const std::shared_ptr<vt::TileTransformer>& tileTransformer) {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_tileTransformer != tileTransformer) {
            _vtRenderer.reset();
        }
        _tileTransformer = tileTransformer;
    }

    void TileRenderer::setInteractionMode(bool enabled) {
        std::lock_guard<std::mutex> lock(_mutex);
        _interactionMode = enabled;
    }

    void TileRenderer::setSubTileBlending(bool enabled) {
        std::lock_guard<std::mutex> lock(_mutex);
        _subTileBlending = enabled;
    }

    void TileRenderer::setLabelOrder(int order) {
        std::lock_guard<std::mutex> lock(_mutex);
        _labelOrder = order;
    }

    void TileRenderer::setBuildingOrder(int order) {
        std::lock_guard<std::mutex> lock(_mutex);
        _buildingOrder = order;
    }

    void TileRenderer::setRasterFilterMode(vt::RasterFilterMode filterMode) {
        std::lock_guard<std::mutex> lock(_mutex);
        _rasterFilterMode = filterMode;
    }

    void TileRenderer::offsetLayerHorizontally(double offset) {
        std::lock_guard<std::mutex> lock(_mutex);
        _horizontalLayerOffset += offset;
    }

    bool TileRenderer::onDrawFrame(float deltaSeconds, const ViewState& viewState) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!initializeRenderer()) {
            return false;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return false;
        }

        cglib::mat4x4<double> modelViewMat = viewState.getModelviewMat() * cglib::translate4_matrix(cglib::vec3<double>(_horizontalLayerOffset, 0, 0));
        tileRenderer->setViewState(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
        tileRenderer->setInteractionMode(_interactionMode);
        tileRenderer->setSubTileBlending(_subTileBlending);
        tileRenderer->setRasterFilterMode(_rasterFilterMode);

        _viewDir = cglib::unit(viewState.getFocusPosNormal());
        if (auto options = _options.lock()) {
            MapPos internalFocusPos = viewState.getProjectionSurface()->calculateMapPos(viewState.getFocusPos());
            _mainLightDir = cglib::vec3<float>::convert(cglib::unit(viewState.getProjectionSurface()->calculateVector(internalFocusPos, options->getMainLightDirection())));
        }

        tileRenderer->startFrame(deltaSeconds * 3);

        bool refresh = false;
        refresh = tileRenderer->renderGeometry2D() || refresh;
        if (_labelOrder == 0) {
            refresh = tileRenderer->renderLabels(true, false) || refresh;
        }
        if (_buildingOrder == 0) {
            refresh = tileRenderer->renderGeometry3D() || refresh;
        }
        if (_labelOrder == 0) {
            refresh = tileRenderer->renderLabels(false, true) || refresh;
        }

        // Reset GL state to the expected state
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);

        GLContext::CheckGLError("TileRenderer::onDrawFrame");
        return refresh;
    }

    bool TileRenderer::onDrawFrame3D(float deltaSeconds, const ViewState& viewState) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_vtRenderer) {
            return false;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return false;
        }

        bool refresh = false;
        if (_labelOrder == 1) {
            refresh = tileRenderer->renderLabels(true, false) || refresh;
        }
        if (_buildingOrder == 1) {
            refresh = tileRenderer->renderGeometry3D() || refresh;
        }
        if (_labelOrder == 1) {
            refresh = tileRenderer->renderLabels(false, true) || refresh;
        }

        tileRenderer->endFrame();

        // Reset GL state to the expected state
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);

        GLContext::CheckGLError("TileRenderer::onDrawFrame3D");
        return refresh;
    }

    bool TileRenderer::cullLabels(vt::LabelCuller& culler, const ViewState& viewState) {
        std::shared_ptr<vt::GLTileRenderer> tileRenderer;
        cglib::mat4x4<double> modelViewMat;
        {
            std::lock_guard<std::mutex> lock(_mutex);

            if (_vtRenderer) {
                tileRenderer = _vtRenderer->getTileRenderer();
            }
            modelViewMat = viewState.getModelviewMat() * cglib::translate4_matrix(cglib::vec3<double>(_horizontalLayerOffset, 0, 0));
        }

        if (!tileRenderer) {
            return false;
        }
        culler.setViewState(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
        tileRenderer->cullLabels(culler);
        return true;
    }

    bool TileRenderer::refreshTiles(const std::vector<std::shared_ptr<TileDrawData> >& drawDatas) {
        std::lock_guard<std::mutex> lock(_mutex);

        std::map<vt::TileId, std::shared_ptr<const vt::Tile> > tiles;
        for (const std::shared_ptr<TileDrawData>& drawData : drawDatas) {
            tiles[drawData->getVTTileId()] = drawData->getVTTile();
        }

        bool changed = (tiles != _tiles) || (_horizontalLayerOffset != 0);
        if (!changed) {
            return false;
        }

        if (_vtRenderer) {
            if (std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer()) {
                tileRenderer->setVisibleTiles(tiles, _horizontalLayerOffset == 0);
            }
        }
        _tiles = std::move(tiles);
        _horizontalLayerOffset = 0;
        return true;
    }

    void TileRenderer::calculateRayIntersectedElements(const cglib::ray3<double>& ray, const ViewState& viewState, float radius, std::vector<std::tuple<vt::TileId, double, long long> >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_vtRenderer) {
            return;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return;
        }

        tileRenderer->findGeometryIntersections(ray, results, radius, true, false);
        if (_labelOrder == 0) {
            tileRenderer->findLabelIntersections(ray, results, radius, true, false);
        }
        if (_buildingOrder == 0) {
            tileRenderer->findGeometryIntersections(ray, results, radius, false, true);
        }
        if (_labelOrder == 0) {
            tileRenderer->findLabelIntersections(ray, results, radius, false, true);
        }
    }

    void TileRenderer::calculateRayIntersectedElements3D(const cglib::ray3<double>& ray, const ViewState& viewState, float radius, std::vector<std::tuple<vt::TileId, double, long long> >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_vtRenderer) {
            return;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return;
        }

        if (_labelOrder == 1) {
            tileRenderer->findLabelIntersections(ray, results, radius, true, false);
        }
        if (_buildingOrder == 1) {
            tileRenderer->findGeometryIntersections(ray, results, radius, false, true);
        }
        if (_labelOrder == 1) {
            tileRenderer->findLabelIntersections(ray, results, radius, false, true);
        }
    }

    void TileRenderer::calculateRayIntersectedBitmaps(const cglib::ray3<double>& ray, const ViewState& viewState, std::vector<std::tuple<vt::TileId, double, vt::TileBitmap, cglib::vec2<float> > >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_vtRenderer) {
            return;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return;
        }

        tileRenderer->findBitmapIntersections(ray, results);
    }

    bool TileRenderer::initializeRenderer() {
        if (_vtRenderer && _vtRenderer->isValid()) {
            return true;
        }

        std::shared_ptr<MapRenderer> mapRenderer = _mapRenderer.lock();
        if (!mapRenderer) {
            return false; // safety check, should never happen
        }

        Log::Debug("TileRenderer: Initializing renderer");
        _vtRenderer = mapRenderer->getGLResourceManager()->create<VTRenderer>(_tileTransformer);

        if (std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer()) {
            tileRenderer->setVisibleTiles(_tiles, _horizontalLayerOffset == 0);

            if (!std::dynamic_pointer_cast<PlanarProjectionSurface>(mapRenderer->getProjectionSurface())) {
                vt::GLTileRenderer::LightingShader lightingShader2D(true, LIGHTING_SHADER_2D, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_viewDir"), 1, _viewDir.data());
                });
                tileRenderer->setLightingShader2D(lightingShader2D);
            }

            vt::GLTileRenderer::LightingShader lightingShader3D(true, LIGHTING_SHADER_3D, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
                if (auto options = _options.lock()) {
                    const Color& ambientLightColor = options->getAmbientLightColor();
                    glUniform4f(glGetUniformLocation(shaderProgram, "u_ambientColor"), ambientLightColor.getR() / 255.0f, ambientLightColor.getG() / 255.0f, ambientLightColor.getB() / 255.0f, ambientLightColor.getA() / 255.0f);
                    const Color& mainLightColor = options->getMainLightColor();
                    glUniform4f(glGetUniformLocation(shaderProgram, "u_lightColor"), mainLightColor.getR() / 255.0f, mainLightColor.getG() / 255.0f, mainLightColor.getB() / 255.0f, mainLightColor.getA() / 255.0f);
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _mainLightDir.data());
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_viewDir"), 1, _viewDir.data());
                }
            });
            tileRenderer->setLightingShader3D(lightingShader3D);

            vt::GLTileRenderer::LightingShader lightingShaderNormalMap(false, LIGHTING_SHADER_NORMALMAP, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
                if (auto options = _options.lock()) {
                    const Color& ambientLightColor = options->getAmbientLightColor();
                    glUniform4f(glGetUniformLocation(shaderProgram, "u_shadowColor"), 0.0f, 0.0f, 0.0f, 1.0f);
                    glUniform4f(glGetUniformLocation(shaderProgram, "u_highlightColor"), 1.0f, 1.0f, 1.0f, 1.0f);
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _mainLightDir.data());
                }
            });
            tileRenderer->setLightingShaderNormalMap(lightingShaderNormalMap);
        }

        return _vtRenderer && _vtRenderer->isValid();
    }

    const std::string TileRenderer::LIGHTING_SHADER_2D = R"GLSL(
        uniform vec3 u_viewDir;
        vec4 applyLighting(lowp vec4 color, mediump vec3 normal) {
            mediump float lighting = max(0.0, dot(normal, u_viewDir)) * 0.5 + 0.5;
            return vec4(color.rgb * lighting, color.a);
        }
    )GLSL";

    const std::string TileRenderer::LIGHTING_SHADER_3D = R"GLSL(
        uniform vec4 u_ambientColor;
        uniform vec4 u_lightColor;
        uniform vec3 u_lightDir;
        uniform vec3 u_viewDir;
        vec4 applyLighting(lowp vec4 color, mediump vec3 normal, highp_opt float height, lowp bool sideVertex) {
            if (sideVertex) {
                lowp vec3 dimmedColor = color.rgb * (1.0 - 0.5 / (1.0 + height * height));
                mediump vec3 lighting = max(0.0, dot(normal, u_lightDir)) * u_lightColor.rgb + u_ambientColor.rgb;
                return vec4(dimmedColor.rgb * lighting, color.a);
            } else {
                mediump float lighting = max(0.0, dot(normal, u_viewDir)) * 0.5 + 0.5;
                return vec4(color.rgb * lighting, color.a);
            }
        }
    )GLSL";

    const std::string TileRenderer::LIGHTING_SHADER_NORMALMAP = R"GLSL(
        uniform vec4 u_shadowColor;
        uniform vec4 u_highlightColor;
        uniform vec3 u_lightDir;
        vec4 applyLighting(lowp vec4 color, mediump vec3 normal, mediump float intensity) {
            mediump float lighting = max(0.0, dot(normal, u_lightDir));
            lowp vec4 shadeColor = mix(u_shadowColor, u_highlightColor, lighting);
            return shadeColor * color * intensity;
        }
    )GLSL";

}
<commit_msg>Fix lighting shader<commit_after>#include "TileRenderer.h"
#include "components/Options.h"
#include "components/ThreadWorker.h"
#include "graphics/ViewState.h"
#include "projections/ProjectionSurface.h"
#include "projections/PlanarProjectionSurface.h"
#include "renderers/MapRenderer.h"
#include "renderers/drawdatas/TileDrawData.h"
#include "renderers/utils/GLResourceManager.h"
#include "renderers/utils/VTRenderer.h"
#include "utils/Log.h"

#include <vt/Label.h>
#include <vt/LabelCuller.h>
#include <vt/TileTransformer.h>
#include <vt/GLTileRenderer.h>
#include <vt/GLExtensions.h>

#include <cglib/mat.h>

namespace carto {

    TileRenderer::TileRenderer() :
        _mapRenderer(),
        _options(),
        _tileTransformer(),
        _vtRenderer(),
        _interactionMode(false),
        _subTileBlending(true),
        _labelOrder(0),
        _buildingOrder(1),
        _rasterFilterMode(vt::RasterFilterMode::BILINEAR),
        _horizontalLayerOffset(0),
        _viewDir(0, 0, 0),
        _mainLightDir(0, 0, 0),
        _tiles(),
        _mutex()
    {
    }

    TileRenderer::~TileRenderer() {
    }

    void TileRenderer::setComponents(const std::weak_ptr<Options>& options, const std::weak_ptr<MapRenderer>& mapRenderer) {
        std::lock_guard<std::mutex> lock(_mutex);
        _options = options;
        _mapRenderer = mapRenderer;
        _vtRenderer.reset();
    }

    std::shared_ptr<vt::TileTransformer> TileRenderer::getTileTransformer() const {
        std::lock_guard<std::mutex> lock(_mutex);
        return _tileTransformer;
    }

    void TileRenderer::setTileTransformer(const std::shared_ptr<vt::TileTransformer>& tileTransformer) {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_tileTransformer != tileTransformer) {
            _vtRenderer.reset();
        }
        _tileTransformer = tileTransformer;
    }

    void TileRenderer::setInteractionMode(bool enabled) {
        std::lock_guard<std::mutex> lock(_mutex);
        _interactionMode = enabled;
    }

    void TileRenderer::setSubTileBlending(bool enabled) {
        std::lock_guard<std::mutex> lock(_mutex);
        _subTileBlending = enabled;
    }

    void TileRenderer::setLabelOrder(int order) {
        std::lock_guard<std::mutex> lock(_mutex);
        _labelOrder = order;
    }

    void TileRenderer::setBuildingOrder(int order) {
        std::lock_guard<std::mutex> lock(_mutex);
        _buildingOrder = order;
    }

    void TileRenderer::setRasterFilterMode(vt::RasterFilterMode filterMode) {
        std::lock_guard<std::mutex> lock(_mutex);
        _rasterFilterMode = filterMode;
    }

    void TileRenderer::offsetLayerHorizontally(double offset) {
        std::lock_guard<std::mutex> lock(_mutex);
        _horizontalLayerOffset += offset;
    }

    bool TileRenderer::onDrawFrame(float deltaSeconds, const ViewState& viewState) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!initializeRenderer()) {
            return false;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return false;
        }

        cglib::mat4x4<double> modelViewMat = viewState.getModelviewMat() * cglib::translate4_matrix(cglib::vec3<double>(_horizontalLayerOffset, 0, 0));
        tileRenderer->setViewState(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
        tileRenderer->setInteractionMode(_interactionMode);
        tileRenderer->setSubTileBlending(_subTileBlending);
        tileRenderer->setRasterFilterMode(_rasterFilterMode);

        _viewDir = cglib::unit(viewState.getFocusPosNormal());
        if (auto options = _options.lock()) {
            MapPos internalFocusPos = viewState.getProjectionSurface()->calculateMapPos(viewState.getFocusPos());
            _mainLightDir = cglib::vec3<float>::convert(cglib::unit(viewState.getProjectionSurface()->calculateVector(internalFocusPos, options->getMainLightDirection())));
        }

        tileRenderer->startFrame(deltaSeconds * 3);

        bool refresh = false;
        refresh = tileRenderer->renderGeometry2D() || refresh;
        if (_labelOrder == 0) {
            refresh = tileRenderer->renderLabels(true, false) || refresh;
        }
        if (_buildingOrder == 0) {
            refresh = tileRenderer->renderGeometry3D() || refresh;
        }
        if (_labelOrder == 0) {
            refresh = tileRenderer->renderLabels(false, true) || refresh;
        }

        // Reset GL state to the expected state
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);

        GLContext::CheckGLError("TileRenderer::onDrawFrame");
        return refresh;
    }

    bool TileRenderer::onDrawFrame3D(float deltaSeconds, const ViewState& viewState) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_vtRenderer) {
            return false;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return false;
        }

        bool refresh = false;
        if (_labelOrder == 1) {
            refresh = tileRenderer->renderLabels(true, false) || refresh;
        }
        if (_buildingOrder == 1) {
            refresh = tileRenderer->renderGeometry3D() || refresh;
        }
        if (_labelOrder == 1) {
            refresh = tileRenderer->renderLabels(false, true) || refresh;
        }

        tileRenderer->endFrame();

        // Reset GL state to the expected state
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);

        GLContext::CheckGLError("TileRenderer::onDrawFrame3D");
        return refresh;
    }

    bool TileRenderer::cullLabels(vt::LabelCuller& culler, const ViewState& viewState) {
        std::shared_ptr<vt::GLTileRenderer> tileRenderer;
        cglib::mat4x4<double> modelViewMat;
        {
            std::lock_guard<std::mutex> lock(_mutex);

            if (_vtRenderer) {
                tileRenderer = _vtRenderer->getTileRenderer();
            }
            modelViewMat = viewState.getModelviewMat() * cglib::translate4_matrix(cglib::vec3<double>(_horizontalLayerOffset, 0, 0));
        }

        if (!tileRenderer) {
            return false;
        }
        culler.setViewState(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
        tileRenderer->cullLabels(culler);
        return true;
    }

    bool TileRenderer::refreshTiles(const std::vector<std::shared_ptr<TileDrawData> >& drawDatas) {
        std::lock_guard<std::mutex> lock(_mutex);

        std::map<vt::TileId, std::shared_ptr<const vt::Tile> > tiles;
        for (const std::shared_ptr<TileDrawData>& drawData : drawDatas) {
            tiles[drawData->getVTTileId()] = drawData->getVTTile();
        }

        bool changed = (tiles != _tiles) || (_horizontalLayerOffset != 0);
        if (!changed) {
            return false;
        }

        if (_vtRenderer) {
            if (std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer()) {
                tileRenderer->setVisibleTiles(tiles, _horizontalLayerOffset == 0);
            }
        }
        _tiles = std::move(tiles);
        _horizontalLayerOffset = 0;
        return true;
    }

    void TileRenderer::calculateRayIntersectedElements(const cglib::ray3<double>& ray, const ViewState& viewState, float radius, std::vector<std::tuple<vt::TileId, double, long long> >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_vtRenderer) {
            return;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return;
        }

        tileRenderer->findGeometryIntersections(ray, results, radius, true, false);
        if (_labelOrder == 0) {
            tileRenderer->findLabelIntersections(ray, results, radius, true, false);
        }
        if (_buildingOrder == 0) {
            tileRenderer->findGeometryIntersections(ray, results, radius, false, true);
        }
        if (_labelOrder == 0) {
            tileRenderer->findLabelIntersections(ray, results, radius, false, true);
        }
    }

    void TileRenderer::calculateRayIntersectedElements3D(const cglib::ray3<double>& ray, const ViewState& viewState, float radius, std::vector<std::tuple<vt::TileId, double, long long> >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_vtRenderer) {
            return;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return;
        }

        if (_labelOrder == 1) {
            tileRenderer->findLabelIntersections(ray, results, radius, true, false);
        }
        if (_buildingOrder == 1) {
            tileRenderer->findGeometryIntersections(ray, results, radius, false, true);
        }
        if (_labelOrder == 1) {
            tileRenderer->findLabelIntersections(ray, results, radius, false, true);
        }
    }

    void TileRenderer::calculateRayIntersectedBitmaps(const cglib::ray3<double>& ray, const ViewState& viewState, std::vector<std::tuple<vt::TileId, double, vt::TileBitmap, cglib::vec2<float> > >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_vtRenderer) {
            return;
        }
        std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer();
        if (!tileRenderer) {
            return;
        }

        tileRenderer->findBitmapIntersections(ray, results);
    }

    bool TileRenderer::initializeRenderer() {
        if (_vtRenderer && _vtRenderer->isValid()) {
            return true;
        }

        std::shared_ptr<MapRenderer> mapRenderer = _mapRenderer.lock();
        if (!mapRenderer) {
            return false; // safety check, should never happen
        }

        Log::Debug("TileRenderer: Initializing renderer");
        _vtRenderer = mapRenderer->getGLResourceManager()->create<VTRenderer>(_tileTransformer);

        if (std::shared_ptr<vt::GLTileRenderer> tileRenderer = _vtRenderer->getTileRenderer()) {
            tileRenderer->setVisibleTiles(_tiles, _horizontalLayerOffset == 0);

            if (!std::dynamic_pointer_cast<PlanarProjectionSurface>(mapRenderer->getProjectionSurface())) {
                vt::GLTileRenderer::LightingShader lightingShader2D(true, LIGHTING_SHADER_2D, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_viewDir"), 1, _viewDir.data());
                });
                tileRenderer->setLightingShader2D(lightingShader2D);
            }

            vt::GLTileRenderer::LightingShader lightingShader3D(true, LIGHTING_SHADER_3D, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
                if (auto options = _options.lock()) {
                    const Color& ambientLightColor = options->getAmbientLightColor();
                    glUniform4f(glGetUniformLocation(shaderProgram, "u_ambientColor"), ambientLightColor.getR() / 255.0f, ambientLightColor.getG() / 255.0f, ambientLightColor.getB() / 255.0f, ambientLightColor.getA() / 255.0f);
                    const Color& mainLightColor = options->getMainLightColor();
                    glUniform4f(glGetUniformLocation(shaderProgram, "u_lightColor"), mainLightColor.getR() / 255.0f, mainLightColor.getG() / 255.0f, mainLightColor.getB() / 255.0f, mainLightColor.getA() / 255.0f);
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _mainLightDir.data());
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_viewDir"), 1, _viewDir.data());
                }
            });
            tileRenderer->setLightingShader3D(lightingShader3D);

            vt::GLTileRenderer::LightingShader lightingShaderNormalMap(false, LIGHTING_SHADER_NORMALMAP, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
                if (auto options = _options.lock()) {
                    const Color& ambientLightColor = options->getAmbientLightColor();
                    glUniform4f(glGetUniformLocation(shaderProgram, "u_shadowColor"), 0.0f, 0.0f, 0.0f, 1.0f);
                    glUniform4f(glGetUniformLocation(shaderProgram, "u_highlightColor"), 1.0f, 1.0f, 1.0f, 1.0f);
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _mainLightDir.data());
                }
            });
            tileRenderer->setLightingShaderNormalMap(lightingShaderNormalMap);
        }

        return _vtRenderer && _vtRenderer->isValid();
    }

    const std::string TileRenderer::LIGHTING_SHADER_2D = R"GLSL(
        uniform vec3 u_viewDir;
        vec4 applyLighting(lowp vec4 color, mediump vec3 normal) {
            mediump float lighting = max(0.0, dot(normal, u_viewDir)) * 0.5 + 0.5;
            return vec4(color.rgb * lighting, color.a);
        }
    )GLSL";

    const std::string TileRenderer::LIGHTING_SHADER_3D = R"GLSL(
        uniform vec4 u_ambientColor;
        uniform vec4 u_lightColor;
        uniform vec3 u_lightDir;
        uniform vec3 u_viewDir;
        vec4 applyLighting(lowp vec4 color, mediump vec3 normal, highp_opt float height, bool sideVertex) {
            if (sideVertex) {
                lowp vec3 dimmedColor = color.rgb * (1.0 - 0.5 / (1.0 + height * height));
                mediump vec3 lighting = max(0.0, dot(normal, u_lightDir)) * u_lightColor.rgb + u_ambientColor.rgb;
                return vec4(dimmedColor.rgb * lighting, color.a);
            } else {
                mediump float lighting = max(0.0, dot(normal, u_viewDir)) * 0.5 + 0.5;
                return vec4(color.rgb * lighting, color.a);
            }
        }
    )GLSL";

    const std::string TileRenderer::LIGHTING_SHADER_NORMALMAP = R"GLSL(
        uniform vec4 u_shadowColor;
        uniform vec4 u_highlightColor;
        uniform vec3 u_lightDir;
        vec4 applyLighting(lowp vec4 color, mediump vec3 normal, mediump float intensity) {
            mediump float lighting = max(0.0, dot(normal, u_lightDir));
            lowp vec4 shadeColor = mix(u_shadowColor, u_highlightColor, lighting);
            return shadeColor * color * intensity;
        }
    )GLSL";

}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Project: BaBar detector at the SLAC PEP-II B-factory
 * Package: RooFitModels
 *    File:
 * Authors:
 *   Jim Smith, jgsmith@pizero.colorado.edu
 * History:
 *   08-Jul-2002 JGS Created initial version
 *
 *****************************************************************************/

// -- CLASS DESCRIPTION [PDF] --
// Implement standard CP physics model with S and C (no mention of lambda)
// Suitably stolen and modified from RooBCPEffDecay

#include <iostream.h>
#include "RooFitCore/RooRealVar.hh"
#include "RooFitCore/RooRandom.hh"
#include "RooFitModels/RooBCPGenDecay.hh"

ClassImp(RooBCPGenDecay)
;

RooBCPGenDecay::RooBCPGenDecay(const char *name, const char *title,
			       RooRealVar& t, RooAbsCategory& tag,
			       RooAbsReal& tau, RooAbsReal& dm,
			       RooAbsReal& avgMistag,
			       RooAbsReal& a, RooAbsReal& b,
			       RooAbsReal& delMistag,
                               RooAbsReal& mu,
			       const RooResolutionModel& model, DecayType type) :
  RooConvolutedPdf(name,title,model,t),
  _avgC("C","Coefficient of cos term",this,a),
  _avgS("S","Coefficient of cos term",this,b),
  _avgMistag("avgMistag","Average mistag rate",this,avgMistag),
  _delMistag("delMistag","Delta mistag rate",this,delMistag),
  _mu("mu","Tagg efficiency difference",this,mu),
  _tag("tag","CP state",this,tag),
  _tau("tau","decay time",this,tau),
  _dm("dm","mixing frequency",this,dm),
  _t("t","time",this,t),
  _type(type),
  _genB0Frac(0)
{
  // Constructor
  switch(type) {
  case SingleSided:
    _basisExp = declareBasis("exp(-@0/@1)",RooArgList(tau,dm)) ;
    _basisSin = declareBasis("exp(-@0/@1)*sin(@0*@2)",RooArgList(tau,dm)) ;
    _basisCos = declareBasis("exp(-@0/@1)*cos(@0*@2)",RooArgList(tau,dm)) ;
    break ;
  case Flipped:
    _basisExp = declareBasis("exp(@0)/@1)",RooArgList(tau,dm)) ;
    _basisSin = declareBasis("exp(@0/@1)*sin(@0*@2)",RooArgList(tau,dm)) ;
    _basisCos = declareBasis("exp(@0/@1)*cos(@0*@2)",RooArgList(tau,dm)) ;
    break ;
  case DoubleSided:
    _basisExp = declareBasis("exp(-abs(@0)/@1)",RooArgList(tau,dm)) ;
    _basisSin = declareBasis("exp(-abs(@0)/@1)*sin(@0*@2)",RooArgList(tau,dm)) ;
    _basisCos = declareBasis("exp(-abs(@0)/@1)*cos(@0*@2)",RooArgList(tau,dm)) ;
    break ;
  }
}

RooBCPGenDecay::RooBCPGenDecay(const RooBCPGenDecay& other, const char* name) :
  RooConvolutedPdf(other,name),
  _avgC("C",this,other._avgC),
  _avgS("S",this,other._avgS),
  _avgMistag("avgMistag",this,other._avgMistag),
  _delMistag("delMistag",this,other._delMistag),
  _mu("mu",this,other._mu),
  _tag("tag",this,other._tag),
  _tau("tau",this,other._tau),
  _dm("dm",this,other._dm),
  _t("t",this,other._t),
  _type(other._type),
  _basisExp(other._basisExp),
  _basisSin(other._basisSin),
  _basisCos(other._basisCos),
  _genB0Frac(other._genB0Frac)
{
  // Copy constructor
}

RooBCPGenDecay::~RooBCPGenDecay()
{
  // Destructor
}

Double_t RooBCPGenDecay::coefficient(Int_t basisIndex) const
{
  // B0    : _tag = +1
  // B0bar : _tag = -1

  if (basisIndex==_basisExp) {
    //exp term: (1 -/+ dw + mu*_tag*w)
    return (1 - _tag*_delMistag + _mu*_tag*(1. - 2.*_avgMistag)) ;
    // =    1 + _tag*deltaDil/2 + _mu*avgDil
  }

  if (basisIndex==_basisSin) {
    //sin term: -(+/- (1-2w) + _mu*(1 +/- delw))*S
    return (_tag*(1-2*_avgMistag) + _mu*(1. + _tag*_delMistag))*_avgS ;
    // =   (_tag*avgDil + _mu*(1 + tag*deltaDil/2)) * S
  }

  if (basisIndex==_basisCos) {
    //cos term: (+/- (1-2w) + _mu*(1 +/- delw))*C
    return 1.*(_tag*(1-2*_avgMistag) + _mu*(1. + _tag*_delMistag))*_avgC ;
    // =   -(_tag*avgDil + _mu*(1 + _tag*deltaDil/2) )* C
  }

  return 0 ;
}

Int_t RooBCPGenDecay::getCoefAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars) const
{
  if (matchArgs(allVars,analVars,_tag)) return 1 ;
  return 0 ;
}

Double_t RooBCPGenDecay::coefAnalyticalIntegral(Int_t basisIndex, Int_t code) const
{
  switch(code) {
    // No integration
  case 0: return coefficient(basisIndex) ;

    // Integration over 'tag'
  case 1:
    if (basisIndex==_basisExp) {
      return 2 ;
    }

    if (basisIndex==_basisSin || basisIndex==_basisCos) {
      return 0 ;
    }
  default:
    assert(0) ;
  }

  return 0 ;
}

Int_t RooBCPGenDecay::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t staticInitOK) const
{
  if (staticInitOK) {
    if (matchArgs(directVars,generateVars,_t,_tag)) return 2 ;
  }
  if (matchArgs(directVars,generateVars,_t)) return 1 ;
  return 0 ;
}

void RooBCPGenDecay::initGenerator(Int_t code)
{
  if (code==2) {
    // Calculate the fraction of mixed events to generate
    Double_t sumInt = RooRealIntegral("sumInt","sum integral",*this,RooArgSet(_t.arg(),_tag.arg())).getVal() ;
    _tag = 1 ;
    Double_t b0Int = RooRealIntegral("mixInt","mix integral",*this,RooArgSet(_t.arg())).getVal() ;
    _genB0Frac = b0Int/sumInt ;
  }
}

void RooBCPGenDecay::generateEvent(Int_t code)
{
  // Generate mix-state dependent
  if (code==2) {
    Double_t rand = RooRandom::uniform() ;
    _tag = (rand<=_genB0Frac) ? 1 : -1 ;
  }

  // Generate delta-t dependent
  while(1) {
    Double_t rand = RooRandom::uniform() ;
    Double_t tval(0) ;

    switch(_type) {
    case SingleSided:
      tval = -_tau*log(rand);
      break ;
    case Flipped:
      tval= +_tau*log(rand);
      break ;
    case DoubleSided:
      tval = (rand<=0.5) ? -_tau*log(2*rand) : +_tau*log(2*(rand-0.5)) ;
      break ;
    }

    // Accept event if T is in generated range
    Double_t maxDil = 1.0 ;
// 2 in next line is conservative and inefficient - allows for delMistag=1!
    Double_t maxAcceptProb = 2 + fabs(maxDil*_avgS) + fabs(maxDil*_avgC);
    Double_t acceptProb    = (1-_tag*_delMistag + _mu*_tag*(1. - 2.*_avgMistag))
                           + (_tag*(1-2*_avgMistag) + _mu*(1. + _tag*_delMistag))*_avgS*sin(_dm*tval)
                           - (_tag*(1-2*_avgMistag) + _mu*(1. + _tag*_delMistag))*_avgC*cos(_dm*tval);

    Bool_t accept = maxAcceptProb*RooRandom::uniform() < acceptProb ? kTRUE : kFALSE ;

    if (tval<_t.max() && tval>_t.min() && accept) {
      _t = tval ;
      break ;
    }
  }

}

<commit_msg>Fix some sign errors in implementation of mu<commit_after>/*****************************************************************************
 * Project: BaBar detector at the SLAC PEP-II B-factory
 * Package: RooFitModels
 *    File:
 * Authors:
 *   Jim Smith, jgsmith@pizero.colorado.edu
 * History:
 *   08-Jul-2002 JGS Created initial version
 *
 *****************************************************************************/

// -- CLASS DESCRIPTION [PDF] --
// Implement standard CP physics model with S and C (no mention of lambda)
// Suitably stolen and modified from RooBCPEffDecay

#include <iostream.h>
#include "RooFitCore/RooRealVar.hh"
#include "RooFitCore/RooRandom.hh"
#include "RooFitModels/RooBCPGenDecay.hh"

ClassImp(RooBCPGenDecay)
;

RooBCPGenDecay::RooBCPGenDecay(const char *name, const char *title,
			       RooRealVar& t, RooAbsCategory& tag,
			       RooAbsReal& tau, RooAbsReal& dm,
			       RooAbsReal& avgMistag,
			       RooAbsReal& a, RooAbsReal& b,
			       RooAbsReal& delMistag,
                               RooAbsReal& mu,
			       const RooResolutionModel& model, DecayType type) :
  RooConvolutedPdf(name,title,model,t),
  _avgC("C","Coefficient of cos term",this,a),
  _avgS("S","Coefficient of cos term",this,b),
  _avgMistag("avgMistag","Average mistag rate",this,avgMistag),
  _delMistag("delMistag","Delta mistag rate",this,delMistag),
  _mu("mu","Tagg efficiency difference",this,mu),
  _tag("tag","CP state",this,tag),
  _tau("tau","decay time",this,tau),
  _dm("dm","mixing frequency",this,dm),
  _t("t","time",this,t),
  _type(type),
  _genB0Frac(0)
{
  // Constructor
  switch(type) {
  case SingleSided:
    _basisExp = declareBasis("exp(-@0/@1)",RooArgList(tau,dm)) ;
    _basisSin = declareBasis("exp(-@0/@1)*sin(@0*@2)",RooArgList(tau,dm)) ;
    _basisCos = declareBasis("exp(-@0/@1)*cos(@0*@2)",RooArgList(tau,dm)) ;
    break ;
  case Flipped:
    _basisExp = declareBasis("exp(@0)/@1)",RooArgList(tau,dm)) ;
    _basisSin = declareBasis("exp(@0/@1)*sin(@0*@2)",RooArgList(tau,dm)) ;
    _basisCos = declareBasis("exp(@0/@1)*cos(@0*@2)",RooArgList(tau,dm)) ;
    break ;
  case DoubleSided:
    _basisExp = declareBasis("exp(-abs(@0)/@1)",RooArgList(tau,dm)) ;
    _basisSin = declareBasis("exp(-abs(@0)/@1)*sin(@0*@2)",RooArgList(tau,dm)) ;
    _basisCos = declareBasis("exp(-abs(@0)/@1)*cos(@0*@2)",RooArgList(tau,dm)) ;
    break ;
  }
}

RooBCPGenDecay::RooBCPGenDecay(const RooBCPGenDecay& other, const char* name) :
  RooConvolutedPdf(other,name),
  _avgC("C",this,other._avgC),
  _avgS("S",this,other._avgS),
  _avgMistag("avgMistag",this,other._avgMistag),
  _delMistag("delMistag",this,other._delMistag),
  _mu("mu",this,other._mu),
  _tag("tag",this,other._tag),
  _tau("tau",this,other._tau),
  _dm("dm",this,other._dm),
  _t("t",this,other._t),
  _type(other._type),
  _basisExp(other._basisExp),
  _basisSin(other._basisSin),
  _basisCos(other._basisCos),
  _genB0Frac(other._genB0Frac)
{
  // Copy constructor
}

RooBCPGenDecay::~RooBCPGenDecay()
{
  // Destructor
}

Double_t RooBCPGenDecay::coefficient(Int_t basisIndex) const
{
  // B0    : _tag = +1
  // B0bar : _tag = -1

  if (basisIndex==_basisExp) {
    //exp term: (1 -/+ dw + mu*_tag*w)
    return (1 - _tag*_delMistag + _mu*_tag*(1. - 2.*_avgMistag)) ;
    // =    1 + _tag*deltaDil/2 + _mu*avgDil
  }

  if (basisIndex==_basisSin) {
    //sin term: (+/- (1-2w) + _mu*(1 -/+ delw))*S
    return (_tag*(1-2*_avgMistag) + _mu*(1. - _tag*_delMistag))*_avgS ;
    // =   (_tag*avgDil + _mu*(1 + tag*deltaDil/2)) * S
  }

  if (basisIndex==_basisCos) {
    //cos term: -(+/- (1-2w) + _mu*(1 -/+ delw))*C
    return -1.*(_tag*(1-2*_avgMistag) + _mu*(1. - _tag*_delMistag))*_avgC ;
    // =   -(_tag*avgDil + _mu*(1 + _tag*deltaDil/2) )* C
  }

  return 0 ;
}

Int_t RooBCPGenDecay::getCoefAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars) const
{
  if (matchArgs(allVars,analVars,_tag)) return 1 ;
  return 0 ;
}

Double_t RooBCPGenDecay::coefAnalyticalIntegral(Int_t basisIndex, Int_t code) const
{
  switch(code) {
    // No integration
  case 0: return coefficient(basisIndex) ;

    // Integration over 'tag'
  case 1:
    if (basisIndex==_basisExp) {
      return 2 ;
    }

    if (basisIndex==_basisSin || basisIndex==_basisCos) {
      return 0 ;
    }
  default:
    assert(0) ;
  }

  return 0 ;
}

Int_t RooBCPGenDecay::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t staticInitOK) const
{
  if (staticInitOK) {
    if (matchArgs(directVars,generateVars,_t,_tag)) return 2 ;
  }
  if (matchArgs(directVars,generateVars,_t)) return 1 ;
  return 0 ;
}

void RooBCPGenDecay::initGenerator(Int_t code)
{
  if (code==2) {
    // Calculate the fraction of mixed events to generate
    Double_t sumInt = RooRealIntegral("sumInt","sum integral",*this,RooArgSet(_t.arg(),_tag.arg())).getVal() ;
    _tag = 1 ;
    Double_t b0Int = RooRealIntegral("mixInt","mix integral",*this,RooArgSet(_t.arg())).getVal() ;
    _genB0Frac = b0Int/sumInt ;
  }
}

void RooBCPGenDecay::generateEvent(Int_t code)
{
  // Generate mix-state dependent
  if (code==2) {
    Double_t rand = RooRandom::uniform() ;
    _tag = (rand<=_genB0Frac) ? 1 : -1 ;
  }

  // Generate delta-t dependent
  while(1) {
    Double_t rand = RooRandom::uniform() ;
    Double_t tval(0) ;

    switch(_type) {
    case SingleSided:
      tval = -_tau*log(rand);
      break ;
    case Flipped:
      tval= +_tau*log(rand);
      break ;
    case DoubleSided:
      tval = (rand<=0.5) ? -_tau*log(2*rand) : +_tau*log(2*(rand-0.5)) ;
      break ;
    }

    // Accept event if T is in generated range
    Double_t maxDil = 1.0 ;
// 2 in next line is conservative and inefficient - allows for delMistag=1!
    Double_t maxAcceptProb = 2 + fabs(maxDil*_avgS) + fabs(maxDil*_avgC);
    Double_t acceptProb    = (1-_tag*_delMistag + _mu*_tag*(1. - 2.*_avgMistag))
                           + (_tag*(1-2*_avgMistag) + _mu*(1. - _tag*_delMistag))*_avgS*sin(_dm*tval)
                           - (_tag*(1-2*_avgMistag) + _mu*(1. - _tag*_delMistag))*_avgC*cos(_dm*tval);

    Bool_t accept = maxAcceptProb*RooRandom::uniform() < acceptProb ? kTRUE : kFALSE ;

    if (tval<_t.max() && tval>_t.min() && accept) {
      _t = tval ;
      break ;
    }
  }

}

<|endoftext|>


<commit_before>// Copyright (c) 2020 by Robert Bosch GmbH, Apex.AI Inc. All rights reserved.
//
// 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 "iceoryx_posh/roudi/roudi_cmd_line_parser.hpp"
#include "iceoryx_posh/internal/log/posh_logging.hpp"
#include "iceoryx_utils/cxx/convert.hpp"
#include "iceoryx_versions.hpp"

#include "iceoryx_utils/platform/getopt.hpp"
#include <iostream>

namespace iox
{
namespace config
{
cxx::expected<CmdLineArgs_t, CmdLineParserResult>
CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cmdLineParsingMode) noexcept
{
    constexpr option longOptions[] = {{"help", no_argument, nullptr, 'h'},
                                      {"version", no_argument, nullptr, 'v'},
                                      {"monitoring-mode", required_argument, nullptr, 'm'},
                                      {"log-level", required_argument, nullptr, 'l'},
                                      {"unique-roudi-id", required_argument, nullptr, 'u'},
                                      {"compatibility", required_argument, nullptr, 'x'},
                                      {"kill-delay", required_argument, nullptr, 'k'},
                                      {nullptr, 0, nullptr, 0}};

    // colon after shortOption means it requires an argument, two colons mean optional argument
    constexpr const char* shortOptions = "hvm:l:u:x:k:";
    int32_t index;
    int32_t opt{-1};
    while ((opt = getopt_long(argc, argv, shortOptions, longOptions, &index), opt != -1))
    {
        switch (opt)
        {
        case 'h':
            std::cout << "Usage: " << argv[0] << " [options]" << std::endl;
            std::cout << "Options:" << std::endl;
            std::cout << "-h, --help                        Display help." << std::endl;
            std::cout << "-v, --version                     Display version." << std::endl;
            std::cout << "-u, --unique-roudi-id <INT>       Set the unique RouDi id." << std::endl;
            std::cout << "-m, --monitoring-mode <MODE>      Set process alive monitoring mode." << std::endl;
            std::cout << "                                  <MODE> {on, off}" << std::endl;
            std::cout << "                                  default = 'on'" << std::endl;
            std::cout << "                                  on: enables monitoring for all processes" << std::endl;
            std::cout << "                                  off: disables monitoring for all processes" << std::endl;
            std::cout << "-l, --log-level <LEVEL>           Set log level." << std::endl;
            std::cout << "                                  <LEVEL> {off, fatal, error, warning, info, debug, verbose}"
                      << std::endl;
            std::cout << "-x, --compatibility               Set compatibility check level between runtime and RouDi."
                      << std::endl;
            std::cout << "                                  off: no check" << std::endl;
            std::cout << "                                  major: same major version " << std::endl;
            std::cout << "                                  minor: same minor version + major check" << std::endl;
            std::cout << "                                  patch: same patch version + minor check" << std::endl;
            std::cout << "                                  commitId: same commit ID + patch check" << std::endl;
            std::cout << "                                  buildDate: same build date + commId check" << std::endl;
            std::cout << "-k, --kill-delay <UINT>           Sets the delay when RouDi sends SIG_KILL, if apps"
                      << std::endl;
            std::cout << "                                  have't responded after trying SIG_TERM first, in seconds."
                      << std::endl;

            m_run = false;
            break;
        case 'v':
            std::cout << "RouDi version: " << ICEORYX_LATEST_RELEASE_VERSION << std::endl;
            std::cout << "Build date: " << ICEORYX_BUILDDATE << std::endl;
            std::cout << "Commit ID: " << ICEORYX_SHA1 << std::endl;
            m_run = false;
            break;
        case 'u':
        {
            uint16_t roudiId{0u};
            constexpr uint64_t MAX_ROUDI_ID = ((1 << 16) - 1);
            if (!cxx::convert::fromString(optarg, roudiId))
            {
                LogError() << "The RouDi id must be in the range of [0, " << MAX_ROUDI_ID << "]";
                m_run = false;
            }

            m_uniqueRouDiId.emplace(roudiId);
            break;
        }
        case 'm':
        {
            if (strcmp(optarg, "on") == 0)
            {
                m_monitoringMode = roudi::MonitoringMode::ON;
            }
            else if (strcmp(optarg, "off") == 0)
            {
                m_monitoringMode = roudi::MonitoringMode::OFF;
            }
            else
            {
                m_run = false;
                LogError() << "Options for monitoring-mode are 'on' and 'off'!";
            }
            break;
        }
        case 'l':
        {
            if (strcmp(optarg, "off") == 0)
            {
                m_logLevel = iox::log::LogLevel::kOff;
            }
            else if (strcmp(optarg, "fatal") == 0)
            {
                m_logLevel = iox::log::LogLevel::kFatal;
            }
            else if (strcmp(optarg, "error") == 0)
            {
                m_logLevel = iox::log::LogLevel::kError;
            }
            else if (strcmp(optarg, "warning") == 0)
            {
                m_logLevel = iox::log::LogLevel::kWarn;
            }
            else if (strcmp(optarg, "info") == 0)
            {
                m_logLevel = iox::log::LogLevel::kInfo;
            }
            else if (strcmp(optarg, "debug") == 0)
            {
                m_logLevel = iox::log::LogLevel::kDebug;
            }
            else if (strcmp(optarg, "verbose") == 0)
            {
                m_logLevel = iox::log::LogLevel::kVerbose;
            }
            else
            {
                m_run = false;
                LogError() << "Options for log-level are 'off', 'fatal', 'error', 'warning', 'info', 'debug' and "
                              "'verbose'!";
            }
            break;
        }
        case 'k':
        {
            uint32_t processKillDelayInSeconds{0u};
            constexpr uint64_t MAX_PROCESS_KILL_DELAY = std::numeric_limits<uint32_t>::max();
            if (!cxx::convert::fromString(optarg, processKillDelayInSeconds))
            {
                LogError() << "The process kill delay must be in the range of [0, " << MAX_PROCESS_KILL_DELAY << "]";
                m_run = false;
            }
            else
            {
                m_processKillDelay =
                    units::Duration::fromSeconds(static_cast<unsigned long long int>(processKillDelayInSeconds));
            }
            break;
        }
        case 'x':
        {
            if (strcmp(optarg, "off") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::OFF;
            }
            else if (strcmp(optarg, "major") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::MAJOR;
            }
            else if (strcmp(optarg, "minor") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::MINOR;
            }
            else if (strcmp(optarg, "patch") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::PATCH;
            }
            else if (strcmp(optarg, "commitId") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::COMMIT_ID;
            }
            else if (strcmp(optarg, "buildDate") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::BUILD_DATE;
            }
            else
            {
                m_run = false;
                LogError()
                    << "Options for compatibility are 'off', 'major', 'minor', 'patch', 'commitId' and 'buildDate'!";
            }
            break;
        }
        default:
        {
            // CmdLineParser did not understand the parameters, don't run
            m_run = false;
            return cxx::error<CmdLineParserResult>(CmdLineParserResult::UNKNOWN_OPTION_USED);
        }
        };

        if (cmdLineParsingMode == CmdLineArgumentParsingMode::ONE)
        {
            break;
        }
    }
    return cxx::success<CmdLineArgs_t>(CmdLineArgs_t{
        m_monitoringMode, m_logLevel, m_compatibilityCheckLevel, m_processKillDelay, m_uniqueRouDiId, m_run, ""});
} // namespace roudi
} // namespace config
} // namespace iox
<commit_msg>iox-#536 removed another unnecessary static_cast<commit_after>// Copyright (c) 2020 by Robert Bosch GmbH, Apex.AI Inc. All rights reserved.
//
// 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 "iceoryx_posh/roudi/roudi_cmd_line_parser.hpp"
#include "iceoryx_posh/internal/log/posh_logging.hpp"
#include "iceoryx_utils/cxx/convert.hpp"
#include "iceoryx_versions.hpp"

#include "iceoryx_utils/platform/getopt.hpp"
#include <iostream>

namespace iox
{
namespace config
{
cxx::expected<CmdLineArgs_t, CmdLineParserResult>
CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cmdLineParsingMode) noexcept
{
    constexpr option longOptions[] = {{"help", no_argument, nullptr, 'h'},
                                      {"version", no_argument, nullptr, 'v'},
                                      {"monitoring-mode", required_argument, nullptr, 'm'},
                                      {"log-level", required_argument, nullptr, 'l'},
                                      {"unique-roudi-id", required_argument, nullptr, 'u'},
                                      {"compatibility", required_argument, nullptr, 'x'},
                                      {"kill-delay", required_argument, nullptr, 'k'},
                                      {nullptr, 0, nullptr, 0}};

    // colon after shortOption means it requires an argument, two colons mean optional argument
    constexpr const char* shortOptions = "hvm:l:u:x:k:";
    int32_t index;
    int32_t opt{-1};
    while ((opt = getopt_long(argc, argv, shortOptions, longOptions, &index), opt != -1))
    {
        switch (opt)
        {
        case 'h':
            std::cout << "Usage: " << argv[0] << " [options]" << std::endl;
            std::cout << "Options:" << std::endl;
            std::cout << "-h, --help                        Display help." << std::endl;
            std::cout << "-v, --version                     Display version." << std::endl;
            std::cout << "-u, --unique-roudi-id <INT>       Set the unique RouDi id." << std::endl;
            std::cout << "-m, --monitoring-mode <MODE>      Set process alive monitoring mode." << std::endl;
            std::cout << "                                  <MODE> {on, off}" << std::endl;
            std::cout << "                                  default = 'on'" << std::endl;
            std::cout << "                                  on: enables monitoring for all processes" << std::endl;
            std::cout << "                                  off: disables monitoring for all processes" << std::endl;
            std::cout << "-l, --log-level <LEVEL>           Set log level." << std::endl;
            std::cout << "                                  <LEVEL> {off, fatal, error, warning, info, debug, verbose}"
                      << std::endl;
            std::cout << "-x, --compatibility               Set compatibility check level between runtime and RouDi."
                      << std::endl;
            std::cout << "                                  off: no check" << std::endl;
            std::cout << "                                  major: same major version " << std::endl;
            std::cout << "                                  minor: same minor version + major check" << std::endl;
            std::cout << "                                  patch: same patch version + minor check" << std::endl;
            std::cout << "                                  commitId: same commit ID + patch check" << std::endl;
            std::cout << "                                  buildDate: same build date + commId check" << std::endl;
            std::cout << "-k, --kill-delay <UINT>           Sets the delay when RouDi sends SIG_KILL, if apps"
                      << std::endl;
            std::cout << "                                  have't responded after trying SIG_TERM first, in seconds."
                      << std::endl;

            m_run = false;
            break;
        case 'v':
            std::cout << "RouDi version: " << ICEORYX_LATEST_RELEASE_VERSION << std::endl;
            std::cout << "Build date: " << ICEORYX_BUILDDATE << std::endl;
            std::cout << "Commit ID: " << ICEORYX_SHA1 << std::endl;
            m_run = false;
            break;
        case 'u':
        {
            uint16_t roudiId{0u};
            constexpr uint64_t MAX_ROUDI_ID = ((1 << 16) - 1);
            if (!cxx::convert::fromString(optarg, roudiId))
            {
                LogError() << "The RouDi id must be in the range of [0, " << MAX_ROUDI_ID << "]";
                m_run = false;
            }

            m_uniqueRouDiId.emplace(roudiId);
            break;
        }
        case 'm':
        {
            if (strcmp(optarg, "on") == 0)
            {
                m_monitoringMode = roudi::MonitoringMode::ON;
            }
            else if (strcmp(optarg, "off") == 0)
            {
                m_monitoringMode = roudi::MonitoringMode::OFF;
            }
            else
            {
                m_run = false;
                LogError() << "Options for monitoring-mode are 'on' and 'off'!";
            }
            break;
        }
        case 'l':
        {
            if (strcmp(optarg, "off") == 0)
            {
                m_logLevel = iox::log::LogLevel::kOff;
            }
            else if (strcmp(optarg, "fatal") == 0)
            {
                m_logLevel = iox::log::LogLevel::kFatal;
            }
            else if (strcmp(optarg, "error") == 0)
            {
                m_logLevel = iox::log::LogLevel::kError;
            }
            else if (strcmp(optarg, "warning") == 0)
            {
                m_logLevel = iox::log::LogLevel::kWarn;
            }
            else if (strcmp(optarg, "info") == 0)
            {
                m_logLevel = iox::log::LogLevel::kInfo;
            }
            else if (strcmp(optarg, "debug") == 0)
            {
                m_logLevel = iox::log::LogLevel::kDebug;
            }
            else if (strcmp(optarg, "verbose") == 0)
            {
                m_logLevel = iox::log::LogLevel::kVerbose;
            }
            else
            {
                m_run = false;
                LogError() << "Options for log-level are 'off', 'fatal', 'error', 'warning', 'info', 'debug' and "
                              "'verbose'!";
            }
            break;
        }
        case 'k':
        {
            uint32_t processKillDelayInSeconds{0u};
            constexpr uint64_t MAX_PROCESS_KILL_DELAY = std::numeric_limits<uint32_t>::max();
            if (!cxx::convert::fromString(optarg, processKillDelayInSeconds))
            {
                LogError() << "The process kill delay must be in the range of [0, " << MAX_PROCESS_KILL_DELAY << "]";
                m_run = false;
            }
            else
            {
                m_processKillDelay =
                    units::Duration::fromSeconds(processKillDelayInSeconds);
            }
            break;
        }
        case 'x':
        {
            if (strcmp(optarg, "off") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::OFF;
            }
            else if (strcmp(optarg, "major") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::MAJOR;
            }
            else if (strcmp(optarg, "minor") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::MINOR;
            }
            else if (strcmp(optarg, "patch") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::PATCH;
            }
            else if (strcmp(optarg, "commitId") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::COMMIT_ID;
            }
            else if (strcmp(optarg, "buildDate") == 0)
            {
                m_compatibilityCheckLevel = iox::version::CompatibilityCheckLevel::BUILD_DATE;
            }
            else
            {
                m_run = false;
                LogError()
                    << "Options for compatibility are 'off', 'major', 'minor', 'patch', 'commitId' and 'buildDate'!";
            }
            break;
        }
        default:
        {
            // CmdLineParser did not understand the parameters, don't run
            m_run = false;
            return cxx::error<CmdLineParserResult>(CmdLineParserResult::UNKNOWN_OPTION_USED);
        }
        };

        if (cmdLineParsingMode == CmdLineArgumentParsingMode::ONE)
        {
            break;
        }
    }
    return cxx::success<CmdLineArgs_t>(CmdLineArgs_t{
        m_monitoringMode, m_logLevel, m_compatibilityCheckLevel, m_processKillDelay, m_uniqueRouDiId, m_run, ""});
} // namespace roudi
} // namespace config
} // namespace iox
<|endoftext|>


<commit_before>// Copyright (c) 2014-2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_INPUT_ERROR_HPP
#define TAO_PEGTL_INPUT_ERROR_HPP

#include <cerrno>
#include <sstream>
#include <stdexcept>

#include "config.hpp"

// In PEGTL 3 input_error was changed to std::system_error and
// std::filesystem::filesystem_error (the latter is derived from the former).
// Here we half-backported it - input_error is replaced with system_error.
#if 0
namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      struct input_error
         : std::runtime_error
      {
         input_error( const std::string& message, const int in_errorno )
            : std::runtime_error( message ),
              errorno( in_errorno )
         {
         }

         int errorno;
      };

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao
#endif

#define TAO_PEGTL_INTERNAL_UNWRAP( ... ) __VA_ARGS__

#define TAO_PEGTL_THROW_INPUT_ERROR( MESSAGE )                                          \
   do {                                                                                \
      const int errorno = errno;                                                        \
      std::ostringstream oss;                                                           \
      oss << TAO_PEGTL_INTERNAL_UNWRAP( MESSAGE ) << " errno " << errorno; \
      throw std::system_error( errorno, std::system_category(), oss.str() );            \
   } while( false )

#endif
<commit_msg>missing header in a previous commit<commit_after>// Copyright (c) 2014-2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_INPUT_ERROR_HPP
#define TAO_PEGTL_INPUT_ERROR_HPP

#include <cerrno>
#include <sstream>
#include <stdexcept>
#include <system_error>

#include "config.hpp"

// In PEGTL 3 input_error was changed to std::system_error and
// std::filesystem::filesystem_error (the latter is derived from the former).
// Here we half-backported it - input_error is replaced with system_error.
#if 0
namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      struct input_error
         : std::runtime_error
      {
         input_error( const std::string& message, const int in_errorno )
            : std::runtime_error( message ),
              errorno( in_errorno )
         {
         }

         int errorno;
      };

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao
#endif

#define TAO_PEGTL_INTERNAL_UNWRAP( ... ) __VA_ARGS__

#define TAO_PEGTL_THROW_INPUT_ERROR( MESSAGE )                                          \
   do {                                                                                \
      const int errorno = errno;                                                        \
      std::ostringstream oss;                                                           \
      oss << TAO_PEGTL_INTERNAL_UNWRAP( MESSAGE ) << " errno " << errorno; \
      throw std::system_error( errorno, std::system_category(), oss.str() );            \
   } while( false )

#endif
<|endoftext|>


<commit_before>#include "ModI2CHost.h"
CModI2CHost::CModI2CHost(void)
{
  // nothing
}

void CModI2CHost::Begin(void)
{
  CModTemplate::Begin();
  ModGUID = 8; // GUID of this sspecific mod

  if (Global.HasUSB) // i2c host only activates if this device is plugged into the PC
  {
    Wire.begin();
  }
}

void CModI2CHost::LoadData(void)
{
  CModTemplate::LoadData();

  if (Global.HasUSB)
  {

  }
}

void CModI2CHost::Loop(void)
{
  CModTemplate::Loop();

  if (Global.HasUSB)
  {
    // syncs templayer value with guest
    if (Global.TempLayer != I2CTempLayer)
    {
      SetTempLayer();
      I2CTempLayer = Global.TempLayer;
    }
    if (Global.LEDBrightness != I2CLEDBrightness)
    {
      SetSubLEDBrightness();
      I2CLEDBrightness = Global.LEDBrightness;
    }
    if (Global.RefreshDelay != I2CRefresh)
    {
      SetSubRefreshRate();
      I2CRefresh = Global.RefreshDelay;
    }
    // gets keystrokes from guest
    Wire.requestFrom(8, 32);
    bool hasInput = true;
    byte keyData[8];
    byte keyType[8];
    byte keyMode[8];
    byte keyX[8];
    byte keyY[8];
    byte keyIndex = 0;
    while (hasInput)
    {

      if (Wire.available()) // need to put ifs in here so trailing bytes are left out
      {
        byte tempByte = Wire.read();
        keyX[keyIndex] = tempByte & 0x0f; // bitwise structure is YYYYXXXX
        keyY[keyIndex] = tempByte >> 4;
      }
      else
      {
        hasInput = false;
      }

      if (Wire.available()) // need to put ifs in here so trailing bytes are left out
      {
        keyData[keyIndex] = Wire.read();
      }
      else
      {
        hasInput = false;
      }

      if (Wire.available()) // need to put ifs in here so trailing bytes are left out
      {
        keyType[keyIndex] = Wire.read();
      }
      else
      {
        hasInput = false;
      }

      if (Wire.available()) // need to put ifs in here so trailing bytes are left out
      {
        keyMode[keyIndex] = Wire.read();
        keyIndex++;
      }
      else
      {
        hasInput = false;
      }
    }

    for (byte i = 0; i < keyIndex; i++)
    {

      if (keyMode[i] == 1) // release key
      {
        Animus.ReleaseKey(keyData[i], keyType[i]);
      }
      else if (keyMode[i] == 5) // press key
      {
        Animus.PrePress(keyData[i], keyType[i]);
        if (Global.TempLayer != I2CTempLayer)
        {
          SetTempLayer();
          I2CTempLayer = Global.TempLayer;
          Wire.beginTransmission(8);
          Wire.write(6);
          Wire.write(keyX[i]);
          Wire.write(keyY[i]);
          Wire.endTransmission();
          Wire.requestFrom(8, 2);
          if (Wire.available()) // need to put ifs in here so trailing bytes are left out
          {
            keyData[i] = Wire.read();
          }
          if (Wire.available()) // need to put ifs in here so trailing bytes are left out
          {
            keyType[i] = Wire.read();
          }
        }
        Animus.PressKey(keyData[i], keyType[i]);
      }
    }
  }

  if (Animus.Async1MSDelay())
  {

    if (Global.HasUSB)
    {

    }
  }

}

void CModI2CHost::PressCoords(byte x, byte y)
{
  CModTemplate::PressCoords(x, y);

  if (Global.HasUSB)
  {

  }

}
void CModI2CHost::PrePress(byte val, byte type)
{
  CModTemplate::PrePress(val, type);
  if (Global.HasUSB)
  {

  }
}
void CModI2CHost::PressKey(byte val, byte type)
{
  CModTemplate::PressKey(val, type);

  if (Global.HasUSB)
  {
  }
}
void CModI2CHost::ReleaseKey(byte val, byte type)
{
  CModTemplate::ReleaseKey(val, type);

  if (Global.HasUSB)
  {

  }
}

void CModI2CHost::SerialComms(byte mode) // holy shit this is complicated
{
  CModTemplate::SerialComms(mode);

  // serial communication

  if (Global.HasUSB)
  {
    if (Comms.mode == 6) // write to guest eeprom starting at addr = 0 or 900, ending at first short read from serial
    {
      EEPROM.update(0, 5);
      if (Serial.available()) //TODO I might want to work in a timeout or fail check for this
      {
        if (SerialLoaderByteStatus == 0) // if this is the first time mode 6 has made contact
        {
          EEPROMPacket[0] = (byte)Serial.read();
          SerialLoaderByteStatus = 1;
          EEPROM.update(0, 6);
        }
        else if (SerialLoaderByteStatus == 1) // if this is the second time mode 6 has made contact
        {
          EEPROMPacket[1] = (byte)Serial.read();
          SerialLoaderByteStatus = 2;
          EEPROM.update(2, 5);

        }
        else if (SerialLoaderByteStatus == 2) // if status is 2, get packet size
        {
          EEPROMPacketSize = (byte)Serial.read();
          SerialLoaderByteStatus = 3;
          EEPROM.update(4, 5);

        }
        else if (SerialLoaderByteStatus == 3) // if mode 6 has obtained the start address and package length
        {
          if (EEPROMPacketSize > 0)
          {
            EEPROMPacket[EEPROMPacketIndex] = (byte)Serial.read();
            EEPROMPacketIndex++;
            EEPROMPacketSize--;
            EEPROM.update(6, 5);
          }
          if (EEPROMPacketSize <= 0)
          {
            EEPROM.update(8, 5);
            SetSubEEPROM();
            EEPROM.update(10, 5);
            EEPROMPacketIndex = 2;
            SerialLoaderByteStatus = 0;
            Comms.mode = 0;
          }
        }
      }
    }
  }
}

// first byte is the type of the packet
// second byte always sends the templayer
// third byte forward is the data of the packet
/*
type 0 does nothing
type 1 sends templayer (templayer)
type 2 is a full reflash type that writes sub eeprom from 0 to 1024 (byte0, byte1, byte2, ...)
type 3 writes sub eeprom starting from 900 (byte0, byte1, byte2, ...)
type 4 changes the LED setting (brightness)
type 5 changes the refresh rate (refresh)
*/

void CModI2CHost::SetTempLayer()
{
  Wire.beginTransmission(8);
  Wire.write(1);
  Wire.write(Global.TempLayer);
  Wire.endTransmission();
}

void CModI2CHost::SetSubEEPROM(void)
{
  Wire.beginTransmission(8);
  Wire.write(2);
  Wire.write(EEPROMPacket, EEPROMPacketIndex);
  Wire.endTransmission();
}

void CModI2CHost::SetSubLEDBrightness(void)
{
  Wire.beginTransmission(8);
  Wire.write(4);
  Wire.write(Global.LEDBrightness);
  Wire.endTransmission();
}

void CModI2CHost::SetSubRefreshRate(void)
{
  Wire.beginTransmission(8);
  Wire.write(5);
  Wire.write(Global.RefreshDelay);
  Wire.endTransmission();
}

CModI2CHost ModI2CHost;
<commit_msg>remove: cleanup debug messages<commit_after>#include "ModI2CHost.h"
CModI2CHost::CModI2CHost(void)
{
  // nothing
}

void CModI2CHost::Begin(void)
{
  CModTemplate::Begin();
  ModGUID = 8; // GUID of this sspecific mod

  if (Global.HasUSB) // i2c host only activates if this device is plugged into the PC
  {
    Wire.begin();
  }
}

void CModI2CHost::LoadData(void)
{
  CModTemplate::LoadData();

  if (Global.HasUSB)
  {

  }
}

void CModI2CHost::Loop(void)
{
  CModTemplate::Loop();

  if (Global.HasUSB)
  {
    // syncs templayer value with guest
    if (Global.TempLayer != I2CTempLayer)
    {
      SetTempLayer();
      I2CTempLayer = Global.TempLayer;
    }
    if (Global.LEDBrightness != I2CLEDBrightness)
    {
      SetSubLEDBrightness();
      I2CLEDBrightness = Global.LEDBrightness;
    }
    if (Global.RefreshDelay != I2CRefresh)
    {
      SetSubRefreshRate();
      I2CRefresh = Global.RefreshDelay;
    }
    // gets keystrokes from guest
    Wire.requestFrom(8, 32);
    bool hasInput = true;
    byte keyData[8];
    byte keyType[8];
    byte keyMode[8];
    byte keyX[8];
    byte keyY[8];
    byte keyIndex = 0;
    while (hasInput)
    {

      if (Wire.available()) // need to put ifs in here so trailing bytes are left out
      {
        byte tempByte = Wire.read();
        keyX[keyIndex] = tempByte & 0x0f; // bitwise structure is YYYYXXXX
        keyY[keyIndex] = tempByte >> 4;
      }
      else
      {
        hasInput = false;
      }

      if (Wire.available()) // need to put ifs in here so trailing bytes are left out
      {
        keyData[keyIndex] = Wire.read();
      }
      else
      {
        hasInput = false;
      }

      if (Wire.available()) // need to put ifs in here so trailing bytes are left out
      {
        keyType[keyIndex] = Wire.read();
      }
      else
      {
        hasInput = false;
      }

      if (Wire.available()) // need to put ifs in here so trailing bytes are left out
      {
        keyMode[keyIndex] = Wire.read();
        keyIndex++;
      }
      else
      {
        hasInput = false;
      }
    }

    for (byte i = 0; i < keyIndex; i++)
    {

      if (keyMode[i] == 1) // release key
      {
        Animus.ReleaseKey(keyData[i], keyType[i]);
      }
      else if (keyMode[i] == 5) // press key
      {
        Animus.PrePress(keyData[i], keyType[i]);
        if (Global.TempLayer != I2CTempLayer)
        {
          SetTempLayer();
          I2CTempLayer = Global.TempLayer;
          Wire.beginTransmission(8);
          Wire.write(6);
          Wire.write(keyX[i]);
          Wire.write(keyY[i]);
          Wire.endTransmission();
          Wire.requestFrom(8, 2);
          if (Wire.available()) // need to put ifs in here so trailing bytes are left out
          {
            keyData[i] = Wire.read();
          }
          if (Wire.available()) // need to put ifs in here so trailing bytes are left out
          {
            keyType[i] = Wire.read();
          }
        }
        Animus.PressKey(keyData[i], keyType[i]);
      }
    }
  }

  if (Animus.Async1MSDelay())
  {

    if (Global.HasUSB)
    {

    }
  }

}

void CModI2CHost::PressCoords(byte x, byte y)
{
  CModTemplate::PressCoords(x, y);

  if (Global.HasUSB)
  {

  }

}
void CModI2CHost::PrePress(byte val, byte type)
{
  CModTemplate::PrePress(val, type);
  if (Global.HasUSB)
  {

  }
}
void CModI2CHost::PressKey(byte val, byte type)
{
  CModTemplate::PressKey(val, type);

  if (Global.HasUSB)
  {
  }
}
void CModI2CHost::ReleaseKey(byte val, byte type)
{
  CModTemplate::ReleaseKey(val, type);

  if (Global.HasUSB)
  {

  }
}

void CModI2CHost::SerialComms(byte mode) // holy shit this is complicated
{
  CModTemplate::SerialComms(mode);

  // serial communication

  if (Global.HasUSB)
  {
    if (Comms.mode == 6) // write to guest eeprom starting at addr = 0 or 900, ending at first short read from serial
    {
      EEPROM.update(0, 5);
      if (Serial.available()) //TODO I might want to work in a timeout or fail check for this
      {
        if (SerialLoaderByteStatus == 0) // if this is the first time mode 6 has made contact
        {
          EEPROMPacket[0] = (byte)Serial.read();
          SerialLoaderByteStatus = 1;
        }
        else if (SerialLoaderByteStatus == 1) // if this is the second time mode 6 has made contact
        {
          EEPROMPacket[1] = (byte)Serial.read();
          SerialLoaderByteStatus = 2;

        }
        else if (SerialLoaderByteStatus == 2) // if status is 2, get packet size
        {
          EEPROMPacketSize = (byte)Serial.read();
          SerialLoaderByteStatus = 3;

        }
        else if (SerialLoaderByteStatus == 3) // if mode 6 has obtained the start address and package length
        {
          if (EEPROMPacketSize > 0)
          {
            EEPROMPacket[EEPROMPacketIndex] = (byte)Serial.read();
            EEPROMPacketIndex++;
            EEPROMPacketSize--;
          }
          if (EEPROMPacketSize <= 0)
          {
            SetSubEEPROM();
            EEPROMPacketIndex = 2;
            SerialLoaderByteStatus = 0;
            Comms.mode = 0;
          }
        }
      }
    }
  }
}

void CModI2CHost::SetTempLayer()
{
  Wire.beginTransmission(8);
  Wire.write(1);
  Wire.write(Global.TempLayer);
  Wire.endTransmission();
}

void CModI2CHost::SetSubEEPROM(void)
{
  Wire.beginTransmission(8);
  Wire.write(2);
  Wire.write(EEPROMPacket, EEPROMPacketIndex);
  Wire.endTransmission();
}

void CModI2CHost::SetSubLEDBrightness(void)
{
  Wire.beginTransmission(8);
  Wire.write(4);
  Wire.write(Global.LEDBrightness);
  Wire.endTransmission();
}

void CModI2CHost::SetSubRefreshRate(void)
{
  Wire.beginTransmission(8);
  Wire.write(5);
  Wire.write(Global.RefreshDelay);
  Wire.endTransmission();
}

CModI2CHost ModI2CHost;
<|endoftext|>