<commit_before>#line 2 "togo/core/lua/lua.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Scripting interface.
@ingroup lib_core_lua
*/

#pragma once

#include <togo/core/config.hpp>
#include <togo/core/types.hpp>
#include <togo/core/error/assert.hpp>
#include <togo/core/utility/traits.hpp>
#include <togo/core/utility/utility.hpp>
#include <togo/core/memory/types.hpp>
#include <togo/core/string/string.hpp>
#include <togo/core/lua/types.hpp>

extern "C" {
	#include <luajit-2.0/lua.h>
	#include <luajit-2.0/lauxlib.h>
	#include <luajit-2.0/lualib.h>
}

#include <togo/core/lua/lua.gen_interface>

namespace togo {
namespace lua {

/**
	@addtogroup lib_core_lua
	@{
*/

/// Push nil to the stack.
inline void push_value(lua_State* L, null_tag const) {
	lua_pushnil(L);
}

/// Push an integral value to the stack.
template<class T>
inline enable_if<is_integral<T>::value, void> push_value(lua_State* L, T value) {
	lua_pushinteger(L, value);
}

/// Get an argument from the stack as an integer.
inline LuaInt get_integer(lua_State* L, signed narg) {
	return luaL_checkinteger(L, narg);
}

/// Push a floating-point value to the stack.
template<class T>
inline enable_if<is_floating_point<T>::value, void> push_value(lua_State* L, T value) {
	lua_pushinteger(L, value);
}

/// Get an argument from the stack as an integer.
inline LuaFloat get_float(lua_State* L, signed narg) {
	return luaL_checknumber(L, narg);
}

// NB: Using template to avoid implicit cast from pointers and integrals.
/// Push a bool to the stack.
template<class T>
inline enable_if<is_same<T, bool>::value, void> push_value(lua_State* L, T value) {
	lua_pushboolean(L, value);
}

/// Get an argument from the stack as a boolean.
inline bool get_boolean(lua_State* L, signed narg) {
	luaL_checktype(L, narg, LUA_TBOOLEAN);
	return lua_toboolean(L, narg);
}

/// Push a string to the stack.
inline void push_value(lua_State* L, StringRef str) {
	lua_pushlstring(L, str.data ? str.data : "", unsigned_cast(str.size));
}

/// Get a string from the stack as a string reference.
inline StringRef get_string(lua_State* L, signed narg) {
	size_t size = 0;
	auto data = luaL_checklstring(L, narg, &size);
	return {data, static_cast<unsigned>(size)};
}

/// Push a C function to the stack.
inline void push_value(lua_State* L, LuaCFunction value) {
	lua_pushcfunction(L, value);
}

/// Get a C function from the stack.
inline LuaCFunction* get_cfunction(lua_State* L, signed narg) {
	luaL_checktype(L, narg, LUA_TFUNCTION);
	return lua_tocfunction(L, narg);
}

/// Set table[name] = value (with settable).
template<class T>
inline void table_set(lua_State* L, signed table, StringRef name, T value) {
	lua::push_value(L, name);
	lua::push_value(L, value);
	lua_settable(L, table);
}

/// Set top_of_stack[name] = value (with settable).
template<class T>
inline void table_set(lua_State* L, StringRef name, T value) {
	lua::table_set(L, -3, name, value);
}

/// Set table[name] = value (with rawset).
template<class T>
inline void table_set_raw(lua_State* L, signed table, StringRef name, T value) {
	lua::push_value(L, name);
	lua::push_value(L, value);
	lua_rawset(L, table);
}

/// Set top_of_stack[name] = value (with rawset).
template<class T>
inline void table_set_raw(lua_State* L, StringRef name, T value) {
	lua::table_set_raw(L, -3, name, value);
}

/// Fetch the value of table[name] and push it on the stack (with gettable).
inline void table_get(lua_State* L, signed table, StringRef name) {
	lua::push_value(L, name);
	lua_gettable(L, table);
}

/// Fetch the value of top_of_stack[name] and push it on the stack (with gettable).
inline void table_get(lua_State* L, StringRef name) {
	lua::table_get(L, -2, name);
}

/// Fetch the value of table[name] and push it on the stack (with rawget).
inline void table_get_raw(lua_State* L, signed table, StringRef name) {
	lua::push_value(L, name);
	lua_rawget(L, table);
}

/// Fetch the value of top_of_stack[name] and push it on the stack (with rawget).
inline void table_get_raw(lua_State* L, StringRef name) {
	lua::table_get_raw(L, -2, name);
}

/// Set table[index] = value (with settable).
template<class T>
inline void table_set_index(lua_State* L, signed table, signed index, T value) {
	lua::push_value(L, index);
	lua::push_value(L, value);
	lua_settable(L, table);
}

/// Set top_of_stack[index] = value (with settable).
template<class T>
inline void table_set_index(lua_State* L, signed index, T value) {
	lua::table_set_index(L, -3, index, value);
}

/// Set table[index] = value (with rawset).
template<class T>
inline void table_set_index_raw(lua_State* L, signed table, signed index, T value) {
	lua::push_value(L, value);
	lua_rawseti(L, table, index);
}

/// Set top_of_stack[index] = value (with rawset).
template<class T>
inline void table_set_index_raw(lua_State* L, signed index, T value) {
	lua::table_set_index_raw(L, -2, index, value);
}

/// Fetch the value of table[index] and push it on the stack (with rawget).
inline void table_get_index(lua_State* L, signed table, signed index) {
	lua::push_value(L, index);
	lua_gettable(L, table);
}

/// Fetch the value of top_of_stack[index] and push it on the stack (with rawget).
inline void table_get_index(lua_State* L, signed index) {
	lua::table_get_index(L, -2, index);
}

/// Fetch the value of table[index] and push it on the stack (with rawget).
inline void table_get_index_raw(lua_State* L, signed table, signed index) {
	lua_rawgeti(L, table, index);
}

/// Fetch the value of top_of_stack[index] and push it on the stack (with rawget).
inline void table_get_index_raw(lua_State* L, signed index) {
	lua::table_get_index_raw(L, -1, index);
}

/// Set table[name] = stack[value] (with settable).
inline void table_set_copy(lua_State* L, signed table, StringRef name, signed value) {
	lua::push_value(L, name);
	lua_pushvalue(L, value - 1);
	lua_settable(L, table);
}

/// Set top_of_stack[name] = stack[value] (with settable).
inline void table_set_copy(lua_State* L, StringRef name, signed value) {
	lua::table_set_copy(L, -3, name, value);
}

/// Set table[name] = stack[value] (with rawset).
inline void table_set_copy_raw(lua_State* L, signed table, StringRef name, signed value) {
	lua::push_value(L, name);
	lua_pushvalue(L, value - 1);
	lua_rawset(L, table);
}

/// Set top_of_stack[name] = stack[value] (with rawset).
inline void table_set_copy_raw(lua_State* L, StringRef name, signed value) {
	lua::table_set_copy_raw(L, -3, name, value);
}

/// Set table[index] = stack[value] (with settable).
inline void table_set_copy_index(lua_State* L, signed table, signed index, signed value) {
	lua::push_value(L, index);
	lua_pushvalue(L, value - 1);
	lua_settable(L, table);
}

/// Set top_of_stack[index] = stack[value] (with settable).
inline void table_set_copy_index(lua_State* L, signed index, signed value) {
	lua::table_set_copy_index(L, -3, index, value);
}

/// Set table[index] = stack[value] (with rawset).
inline void table_set_copy_index_raw(lua_State* L, signed table, signed index, signed value) {
	lua_pushvalue(L, value);
	lua_rawseti(L, table, index);
}

/// Set top_of_stack[index] = stack[value] (with rawset).
inline void table_set_copy_index_raw(lua_State* L, signed index, signed value) {
	lua::table_set_copy_index_raw(L, -2, index, value);
}

template<class T>
inline void register_userdata(lua_State* L, LuaCFunction destroy) {
	lua::table_get_raw(L, LUA_REGISTRYINDEX, "togo_class");
	TOGO_ASSERT(!lua_isnil(L, -1), "core was not registered");

	lua::table_get_raw(L, T::lua_metatable_name);
	TOGO_ASSERT(lua_isnil(L, -1), "class metatable was already registered");
	lua_pop(L, 1);

	lua_createtable(L, 0, 1);
	lua::table_set_raw(L, "__gc", destroy);

	// togo_class[T::lua_metatable_name] = metatable
	lua::table_set_copy_raw(L, -4, T::lua_metatable_name, -1);
	lua_pop(L, 2); // metatable, togo_class
}

/// Push a new userdata to the stack and setup its metatable.
template<class T, class... P>
inline T* new_userdata(lua_State* L, P&&... p) {
	auto* ptr = lua_newuserdata(L, sizeof(T));
	TOGO_DEBUG_ASSERTE(ptr);

	lua::table_get_raw(L, LUA_REGISTRYINDEX, "togo_class");
	TOGO_ASSERT(!lua_isnil(L, -1), "core was not registered");
	lua::table_get_raw(L, T::lua_metatable_name);
	TOGO_ASSERT(!lua_isnil(L, -1), "class metatable was not registered");
	lua_setmetatable(L, -3);
	lua_pop(L, 1);

	return new(ptr) T(p...);
}

/// Get an argument from the stack as userdata (typed).
template<class T>
inline T* get_userdata(lua_State* L, signed narg, bool require = true) {
	{auto type = lua_type(L, narg);
	if (type != LUA_TUSERDATA && type != LUA_TNIL) {
		luaL_argerror(L, narg, "expected userdata");
	}}
	auto p = lua_touserdata(L, narg);
	if (require && !p) {
		luaL_argerror(L, narg, "value must be non-null");
	} else {
		if (!lua_getmetatable(L, narg)) {
			luaL_argerror(L, narg, "expected a metatable for userdata, but it has none");
		}
		lua::table_get_raw(L, LUA_REGISTRYINDEX, "togo_class");
		TOGO_ASSERT(!lua_isnil(L, -1), "core was not registered");
		lua::table_get_raw(L, T::lua_metatable_name);
		TOGO_ASSERT(!lua_isnil(L, -1), "class metatable was not registered");
		if (!lua_rawequal(L, -1, -3)) {
			luaL_argerror(L, narg, "userdata metatable does not match the expected one");
		}
		lua_pop(L, 3);
	}
	return static_cast<T*>(p);
}

/// Push a light userdata to the stack or nil if the pointer is null.
inline void push_lightuserdata(lua_State* L, void* p) {
	if (p) {
		lua_pushlightuserdata(L, p);
	} else {
		lua_pushnil(L);
	}
}

/// Get an argument from the stack as light userdata.
inline void* get_lightuserdata(lua_State* L, signed narg, bool require = true) {
	{auto type = lua_type(L, narg);
	if (type != LUA_TLIGHTUSERDATA && type != LUA_TNIL) {
		luaL_argerror(L, narg, "expected light userdata");
	}}
	auto p = lua_touserdata(L, narg);
	if (require && !p) {
		luaL_argerror(L, narg, "value must be non-null");
	}
	return p;
}

/// Get an argument from the stack as light userdata (typed).
///
/// This is an unchecked cast.
template<class T>
inline T* get_lightuserdata_typed(lua_State* L, signed narg, bool require = true) {
	return static_cast<T*>(get_lightuserdata(L, narg, require));
}

/** @} */ // end of doc-group lib_core_lua

} // namespace lua
} // namespace togo
<commit_msg>lib/core/lua: set userdata __index metamethod to the metatable.¹<commit_after>#line 2 "togo/core/lua/lua.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Scripting interface.
@ingroup lib_core_lua
*/

#pragma once

#include <togo/core/config.hpp>
#include <togo/core/types.hpp>
#include <togo/core/error/assert.hpp>
#include <togo/core/utility/traits.hpp>
#include <togo/core/utility/utility.hpp>
#include <togo/core/memory/types.hpp>
#include <togo/core/string/string.hpp>
#include <togo/core/lua/types.hpp>

extern "C" {
	#include <luajit-2.0/lua.h>
	#include <luajit-2.0/lauxlib.h>
	#include <luajit-2.0/lualib.h>
}

#include <togo/core/lua/lua.gen_interface>

namespace togo {
namespace lua {

/**
	@addtogroup lib_core_lua
	@{
*/

/// Push nil to the stack.
inline void push_value(lua_State* L, null_tag const) {
	lua_pushnil(L);
}

/// Push an integral value to the stack.
template<class T>
inline enable_if<is_integral<T>::value, void> push_value(lua_State* L, T value) {
	lua_pushinteger(L, value);
}

/// Get an argument from the stack as an integer.
inline LuaInt get_integer(lua_State* L, signed narg) {
	return luaL_checkinteger(L, narg);
}

/// Push a floating-point value to the stack.
template<class T>
inline enable_if<is_floating_point<T>::value, void> push_value(lua_State* L, T value) {
	lua_pushinteger(L, value);
}

/// Get an argument from the stack as an integer.
inline LuaFloat get_float(lua_State* L, signed narg) {
	return luaL_checknumber(L, narg);
}

// NB: Using template to avoid implicit cast from pointers and integrals.
/// Push a bool to the stack.
template<class T>
inline enable_if<is_same<T, bool>::value, void> push_value(lua_State* L, T value) {
	lua_pushboolean(L, value);
}

/// Get an argument from the stack as a boolean.
inline bool get_boolean(lua_State* L, signed narg) {
	luaL_checktype(L, narg, LUA_TBOOLEAN);
	return lua_toboolean(L, narg);
}

/// Push a string to the stack.
inline void push_value(lua_State* L, StringRef str) {
	lua_pushlstring(L, str.data ? str.data : "", unsigned_cast(str.size));
}

/// Get a string from the stack as a string reference.
inline StringRef get_string(lua_State* L, signed narg) {
	size_t size = 0;
	auto data = luaL_checklstring(L, narg, &size);
	return {data, static_cast<unsigned>(size)};
}

/// Push a C function to the stack.
inline void push_value(lua_State* L, LuaCFunction value) {
	lua_pushcfunction(L, value);
}

/// Get a C function from the stack.
inline LuaCFunction* get_cfunction(lua_State* L, signed narg) {
	luaL_checktype(L, narg, LUA_TFUNCTION);
	return lua_tocfunction(L, narg);
}

/// Set table[name] = value (with settable).
template<class T>
inline void table_set(lua_State* L, signed table, StringRef name, T value) {
	lua::push_value(L, name);
	lua::push_value(L, value);
	lua_settable(L, table);
}

/// Set top_of_stack[name] = value (with settable).
template<class T>
inline void table_set(lua_State* L, StringRef name, T value) {
	lua::table_set(L, -3, name, value);
}

/// Set table[name] = value (with rawset).
template<class T>
inline void table_set_raw(lua_State* L, signed table, StringRef name, T value) {
	lua::push_value(L, name);
	lua::push_value(L, value);
	lua_rawset(L, table);
}

/// Set top_of_stack[name] = value (with rawset).
template<class T>
inline void table_set_raw(lua_State* L, StringRef name, T value) {
	lua::table_set_raw(L, -3, name, value);
}

/// Fetch the value of table[name] and push it on the stack (with gettable).
inline void table_get(lua_State* L, signed table, StringRef name) {
	lua::push_value(L, name);
	lua_gettable(L, table);
}

/// Fetch the value of top_of_stack[name] and push it on the stack (with gettable).
inline void table_get(lua_State* L, StringRef name) {
	lua::table_get(L, -2, name);
}

/// Fetch the value of table[name] and push it on the stack (with rawget).
inline void table_get_raw(lua_State* L, signed table, StringRef name) {
	lua::push_value(L, name);
	lua_rawget(L, table);
}

/// Fetch the value of top_of_stack[name] and push it on the stack (with rawget).
inline void table_get_raw(lua_State* L, StringRef name) {
	lua::table_get_raw(L, -2, name);
}

/// Set table[index] = value (with settable).
template<class T>
inline void table_set_index(lua_State* L, signed table, signed index, T value) {
	lua::push_value(L, index);
	lua::push_value(L, value);
	lua_settable(L, table);
}

/// Set top_of_stack[index] = value (with settable).
template<class T>
inline void table_set_index(lua_State* L, signed index, T value) {
	lua::table_set_index(L, -3, index, value);
}

/// Set table[index] = value (with rawset).
template<class T>
inline void table_set_index_raw(lua_State* L, signed table, signed index, T value) {
	lua::push_value(L, value);
	lua_rawseti(L, table, index);
}

/// Set top_of_stack[index] = value (with rawset).
template<class T>
inline void table_set_index_raw(lua_State* L, signed index, T value) {
	lua::table_set_index_raw(L, -2, index, value);
}

/// Fetch the value of table[index] and push it on the stack (with rawget).
inline void table_get_index(lua_State* L, signed table, signed index) {
	lua::push_value(L, index);
	lua_gettable(L, table);
}

/// Fetch the value of top_of_stack[index] and push it on the stack (with rawget).
inline void table_get_index(lua_State* L, signed index) {
	lua::table_get_index(L, -2, index);
}

/// Fetch the value of table[index] and push it on the stack (with rawget).
inline void table_get_index_raw(lua_State* L, signed table, signed index) {
	lua_rawgeti(L, table, index);
}

/// Fetch the value of top_of_stack[index] and push it on the stack (with rawget).
inline void table_get_index_raw(lua_State* L, signed index) {
	lua::table_get_index_raw(L, -1, index);
}

/// Set table[name] = stack[value] (with settable).
inline void table_set_copy(lua_State* L, signed table, StringRef name, signed value) {
	lua::push_value(L, name);
	lua_pushvalue(L, value - 1);
	lua_settable(L, table);
}

/// Set top_of_stack[name] = stack[value] (with settable).
inline void table_set_copy(lua_State* L, StringRef name, signed value) {
	lua::table_set_copy(L, -3, name, value);
}

/// Set table[name] = stack[value] (with rawset).
inline void table_set_copy_raw(lua_State* L, signed table, StringRef name, signed value) {
	lua::push_value(L, name);
	lua_pushvalue(L, value - 1);
	lua_rawset(L, table);
}

/// Set top_of_stack[name] = stack[value] (with rawset).
inline void table_set_copy_raw(lua_State* L, StringRef name, signed value) {
	lua::table_set_copy_raw(L, -3, name, value);
}

/// Set table[index] = stack[value] (with settable).
inline void table_set_copy_index(lua_State* L, signed table, signed index, signed value) {
	lua::push_value(L, index);
	lua_pushvalue(L, value - 1);
	lua_settable(L, table);
}

/// Set top_of_stack[index] = stack[value] (with settable).
inline void table_set_copy_index(lua_State* L, signed index, signed value) {
	lua::table_set_copy_index(L, -3, index, value);
}

/// Set table[index] = stack[value] (with rawset).
inline void table_set_copy_index_raw(lua_State* L, signed table, signed index, signed value) {
	lua_pushvalue(L, value);
	lua_rawseti(L, table, index);
}

/// Set top_of_stack[index] = stack[value] (with rawset).
inline void table_set_copy_index_raw(lua_State* L, signed index, signed value) {
	lua::table_set_copy_index_raw(L, -2, index, value);
}

template<class T>
inline void register_userdata(lua_State* L, LuaCFunction destroy) {
	lua::table_get_raw(L, LUA_REGISTRYINDEX, "togo_class");
	TOGO_ASSERT(!lua_isnil(L, -1), "core was not registered");

	lua::table_get_raw(L, T::lua_metatable_name);
	TOGO_ASSERT(lua_isnil(L, -1), "class metatable was already registered");
	lua_pop(L, 1);

	lua_createtable(L, 0, 1);
	lua::table_set_copy_raw(L, "__index", -1);
	lua::table_set_raw(L, "__gc", destroy);

	// togo_class[T::lua_metatable_name] = metatable
	lua::table_set_copy_raw(L, -4, T::lua_metatable_name, -1);
	lua_pop(L, 2); // metatable, togo_class
}

/// Push a new userdata to the stack and setup its metatable.
template<class T, class... P>
inline T* new_userdata(lua_State* L, P&&... p) {
	auto* ptr = lua_newuserdata(L, sizeof(T));
	TOGO_DEBUG_ASSERTE(ptr);

	lua::table_get_raw(L, LUA_REGISTRYINDEX, "togo_class");
	TOGO_ASSERT(!lua_isnil(L, -1), "core was not registered");
	lua::table_get_raw(L, T::lua_metatable_name);
	TOGO_ASSERT(!lua_isnil(L, -1), "class metatable was not registered");
	lua_setmetatable(L, -3);
	lua_pop(L, 1);

	return new(ptr) T(p...);
}

/// Get an argument from the stack as userdata (typed).
template<class T>
inline T* get_userdata(lua_State* L, signed narg, bool require = true) {
	{auto type = lua_type(L, narg);
	if (type != LUA_TUSERDATA && type != LUA_TNIL) {
		luaL_argerror(L, narg, "expected userdata");
	}}
	auto p = lua_touserdata(L, narg);
	if (require && !p) {
		luaL_argerror(L, narg, "value must be non-null");
	} else {
		if (!lua_getmetatable(L, narg)) {
			luaL_argerror(L, narg, "expected a metatable for userdata, but it has none");
		}
		lua::table_get_raw(L, LUA_REGISTRYINDEX, "togo_class");
		TOGO_ASSERT(!lua_isnil(L, -1), "core was not registered");
		lua::table_get_raw(L, T::lua_metatable_name);
		TOGO_ASSERT(!lua_isnil(L, -1), "class metatable was not registered");
		if (!lua_rawequal(L, -1, -3)) {
			luaL_argerror(L, narg, "userdata metatable does not match the expected one");
		}
		lua_pop(L, 3);
	}
	return static_cast<T*>(p);
}

/// Push a light userdata to the stack or nil if the pointer is null.
inline void push_lightuserdata(lua_State* L, void* p) {
	if (p) {
		lua_pushlightuserdata(L, p);
	} else {
		lua_pushnil(L);
	}
}

/// Get an argument from the stack as light userdata.
inline void* get_lightuserdata(lua_State* L, signed narg, bool require = true) {
	{auto type = lua_type(L, narg);
	if (type != LUA_TLIGHTUSERDATA && type != LUA_TNIL) {
		luaL_argerror(L, narg, "expected light userdata");
	}}
	auto p = lua_touserdata(L, narg);
	if (require && !p) {
		luaL_argerror(L, narg, "value must be non-null");
	}
	return p;
}

/// Get an argument from the stack as light userdata (typed).
///
/// This is an unchecked cast.
template<class T>
inline T* get_lightuserdata_typed(lua_State* L, signed narg, bool require = true) {
	return static_cast<T*>(get_lightuserdata(L, narg, require));
}

/** @} */ // end of doc-group lib_core_lua

} // namespace lua
} // namespace togo
<|endoftext|>


<commit_before>#pragma once

#include "simlib/string_view.hh"

// Returns an absolute path that does not contain any . or .. components,
// nor any repeated path separators (/). @p curr_dir can be empty. If path
// begins with / then @p curr_dir is ignored.
std::string path_absolute(StringView path, std::string curr_dir = "/");

/**
 * @brief Returns the filename (last non-directory component) of the @p path
 * @details Examples:
 *   "/my/path/foo.bar" -> "foo.bar"
 *   "/my/path/" -> ""
 *   "/" -> ""
 *   "/my/path/." -> "."
 *   "/my/path/.." -> ".."
 *   "foo" -> "foo"
 */
template <class T>
constexpr auto path_filename(T&& path) noexcept {
	using RetType = std::conditional_t<std::is_convertible_v<T, CStringView>,
	                                   CStringView, StringView>;
	RetType path_str(std::forward<T>(path));
	auto pos = path_str.rfind('/');
	return path_str.substr(pos == path_str.npos ? 0 : pos + 1);
}

// Returns extension (without dot) e.g. "foo.cc" -> "cc", "bar" -> ""
template <class T>
constexpr auto path_extension(T&& path) noexcept {
	using RetType = std::conditional_t<std::is_convertible_v<T, CStringView>,
	                                   CStringView, StringView>;

	RetType path_str(std::forward<T>(path));
	size_t start_pos = path_str.rfind('/');
	if (start_pos == path_str.npos) {
		start_pos = 0;
	} else {
		++start_pos;
	}

	size_t x = path_str.rfind('.', start_pos);
	if (x == path_str.npos) {
		return RetType{}; // No extension
	}

	return path_str.substr(x + 1);
}

/**
 * @brief Returns the dirpath of the path @p path
 * @details Examples:
 *   "/my/path/foo.bar" -> "/my/path/"
 *   "/my/path/" -> "/my/path/"
 *   "/" -> "/"
 *   "/my/path/." -> "/my/path/"
 *   "/my/path/.." -> "/my/path/"
 *   "abc/efg" -> "abc/"
 *   "foo" -> ""
 */
constexpr inline StringView path_dirpath(const StringView& path) noexcept {
	auto pos = path.rfind('/');
	return path.substring(0, pos == StringView::npos ? 0 : pos + 1);
}

/**
 * @brief Checks every ancestor (parent) directory of @p path if it has @p
 *   subpath and if true returns path of @p subpath in ancestor directory
 * @details Examples:
 *   1) @p path == "a/b/c/file", @p subpath == "/x/y/z", tried paths will be:
 *     "a/b/c/x/y/z"
 *     "a/b/x/y/z"
 *     "a/x/y/z"
 *     "x/y/z"
 *   2) @p path == "/a/b/c/", @p subpath == "x/y/", tried paths will be:
 *     "/a/b/c/x/y/"
 *     "/a/b/x/y/"
 *     "/a/x/y/"
 *     "/x/y/"
 */
std::optional<std::string>
deepest_ancestor_dir_with_subpath(std::string path, StringView subpath);
<commit_msg>path.hh: fixed doc comment<commit_after>#pragma once

#include "simlib/string_view.hh"

// Returns an absolute path that does not contain any . or .. components,
// nor any repeated path separators (/). @p curr_dir can be empty. If path
// begins with / then @p curr_dir is ignored.
std::string path_absolute(StringView path, std::string curr_dir = "/");

/**
 * @brief Returns the filename (last non-directory component) of the @p path
 * @details Examples:
 *   "/my/path/foo.bar" -> "foo.bar"
 *   "/my/path/" -> ""
 *   "/" -> ""
 *   "/my/path/." -> "."
 *   "/my/path/.." -> ".."
 *   "foo" -> "foo"
 */
template <class T>
constexpr auto path_filename(T&& path) noexcept {
	using RetType = std::conditional_t<std::is_convertible_v<T, CStringView>,
	                                   CStringView, StringView>;
	RetType path_str(std::forward<T>(path));
	auto pos = path_str.rfind('/');
	return path_str.substr(pos == path_str.npos ? 0 : pos + 1);
}

// Returns extension (without dot) e.g. "foo.cc" -> "cc", "bar" -> ""
template <class T>
constexpr auto path_extension(T&& path) noexcept {
	using RetType = std::conditional_t<std::is_convertible_v<T, CStringView>,
	                                   CStringView, StringView>;

	RetType path_str(std::forward<T>(path));
	size_t start_pos = path_str.rfind('/');
	if (start_pos == path_str.npos) {
		start_pos = 0;
	} else {
		++start_pos;
	}

	size_t x = path_str.rfind('.', start_pos);
	if (x == path_str.npos) {
		return RetType{}; // No extension
	}

	return path_str.substr(x + 1);
}

/**
 * @brief Returns prefix of the @p path that is a dirpath of the @p path
 * @details Examples:
 *   "/my/path/foo.bar" -> "/my/path/"
 *   "/my/path/" -> "/my/path/"
 *   "/" -> "/"
 *   "/my/path/." -> "/my/path/"
 *   "/my/path/.." -> "/my/path/"
 *   "abc/efg" -> "abc/"
 *   "foo" -> ""
 */
constexpr inline StringView path_dirpath(const StringView& path) noexcept {
	auto pos = path.rfind('/');
	return path.substring(0, pos == StringView::npos ? 0 : pos + 1);
}

/**
 * @brief Checks every ancestor (parent) directory of @p path if it has @p
 *   subpath and if true returns path of @p subpath in ancestor directory
 * @details Examples:
 *   1) @p path == "a/b/c/file", @p subpath == "/x/y/z", tried paths will be:
 *     "a/b/c/x/y/z"
 *     "a/b/x/y/z"
 *     "a/x/y/z"
 *     "x/y/z"
 *   2) @p path == "/a/b/c/", @p subpath == "x/y/", tried paths will be:
 *     "/a/b/c/x/y/"
 *     "/a/b/x/y/"
 *     "/a/x/y/"
 *     "/x/y/"
 */
std::optional<std::string>
deepest_ancestor_dir_with_subpath(std::string path, StringView subpath);
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

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

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

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

#include "render_world.h"
#include "device.h"
#include "allocator.h"
#include "camera.h"
#include "resource.h"
#include "log.h"
#include "sprite_resource.h"
#include "mesh.h"
#include "sprite.h"
#include "material.h"
#include "config.h"
#include "gui.h"
#include <bgfx.h>

#include "material_manager.h"

namespace crown
{

namespace graphics_system
{
	void init()
	{
		bgfx::init();
	}

	void shutdown()
	{
		bgfx::shutdown();
	}
};

//-----------------------------------------------------------------------------
RenderWorld::RenderWorld()
	: m_mesh_pool(default_allocator(), MAX_MESHES, sizeof(Mesh), CE_ALIGNOF(Mesh))
	, m_sprite_pool(default_allocator(), MAX_SPRITES, sizeof(Sprite), CE_ALIGNOF(Sprite))
	, m_gui_pool(default_allocator(), MAX_GUIS, sizeof(Gui), CE_ALIGNOF(Gui))
{
}

//-----------------------------------------------------------------------------
RenderWorld::~RenderWorld()
{
}

//-----------------------------------------------------------------------------
MeshId RenderWorld::create_mesh(MeshResource* mr, SceneGraph& sg, int32_t node)
{
	Mesh* mesh = CE_NEW(m_mesh_pool, Mesh)(sg, node, mr);
	return id_array::create(m_mesh, mesh);
}

//-----------------------------------------------------------------------------
void RenderWorld::destroy_mesh(MeshId id)
{
	Mesh* mesh = id_array::get(m_mesh, id);
	CE_DELETE(m_mesh_pool, mesh);
	id_array::destroy(m_mesh, id);
}

//-----------------------------------------------------------------------------
Mesh* RenderWorld::get_mesh(MeshId mesh)
{
	return id_array::get(m_mesh, mesh);
}

//-----------------------------------------------------------------------------
SpriteId RenderWorld::create_sprite(SpriteResource* sr, SceneGraph& sg, int32_t node)
{
	Sprite* sprite = CE_NEW(m_sprite_pool, Sprite)(*this, sg, node, sr);
	return id_array::create(m_sprite, sprite);
}

//-----------------------------------------------------------------------------
void RenderWorld::destroy_sprite(SpriteId id)
{
	CE_DELETE(m_sprite_pool, id_array::get(m_sprite, id));
	id_array::destroy(m_sprite, id);
}

//-----------------------------------------------------------------------------
Sprite*	RenderWorld::get_sprite(SpriteId id)
{
	return id_array::get(m_sprite, id);
}

//-----------------------------------------------------------------------------
GuiId RenderWorld::create_gui(uint16_t width, uint16_t height, const char* material)
{
	Gui* gui = CE_NEW(m_gui_pool, Gui)(width, height, material);
	GuiId id = id_array::create(m_guis, gui);
	gui->set_id(id);
	return id;
}

//-----------------------------------------------------------------------------
void RenderWorld::destroy_gui(GuiId id)
{
	CE_DELETE(m_gui_pool, id_array::get(m_guis, id));
	id_array::destroy(m_guis, id);
}

//-----------------------------------------------------------------------------
Gui* RenderWorld::get_gui(GuiId id)
{
	return id_array::get(m_guis, id);
}

//-----------------------------------------------------------------------------
void RenderWorld::update(const Matrix4x4& view, const Matrix4x4& projection, uint16_t x, uint16_t y, uint16_t width, uint16_t height, float dt)
{
	bgfx::reset(width, height, BGFX_RESET_VSYNC);

	// Enable debug text.
	bgfx::setDebug(BGFX_DEBUG_TEXT);

	// Set view 0 clear state.
	bgfx::setViewClear(0
		, BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT
		, 0x353839FF
		, 1.0f
		, 0
		);

	// Set view and projection matrix for view 0.
	Matrix4x4 inv_view = view;
	matrix4x4::invert(inv_view);
	bgfx::setViewTransform(0, matrix4x4::to_float_ptr(inv_view), matrix4x4::to_float_ptr(projection));

	bgfx::setViewRect(0, 0, 0, width, height);

	// This dummy draw call is here to make sure that view 0 is cleared
	// if no other draw calls are submitted to view 0.
	bgfx::submit(0);

	// Use debug font to print information about this example.
	bgfx::dbgTextClear();
	bgfx::dbgTextPrintf(0, 2, 0x6f, "dt = %4.7f", dt);

	// Draw all sprites
	for (uint32_t s = 0; s < id_array::size(m_sprite); s++)
	{
		m_sprite[s]->render();
	}

	// Advance to next frame. Rendering thread will be kicked to
	// process submitted rendering primitives.
	bgfx::frame();
}

} // namespace crown
<commit_msg>Do not invert view matrix<commit_after>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

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

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

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

#include "render_world.h"
#include "device.h"
#include "allocator.h"
#include "camera.h"
#include "resource.h"
#include "log.h"
#include "sprite_resource.h"
#include "mesh.h"
#include "sprite.h"
#include "material.h"
#include "config.h"
#include "gui.h"
#include <bgfx.h>
#include <bx/fpumath.h>

#include "material_manager.h"

namespace crown
{

namespace graphics_system
{
	void init()
	{
		bgfx::init();
	}

	void shutdown()
	{
		bgfx::shutdown();
	}
};

//-----------------------------------------------------------------------------
RenderWorld::RenderWorld()
	: m_mesh_pool(default_allocator(), MAX_MESHES, sizeof(Mesh), CE_ALIGNOF(Mesh))
	, m_sprite_pool(default_allocator(), MAX_SPRITES, sizeof(Sprite), CE_ALIGNOF(Sprite))
	, m_gui_pool(default_allocator(), MAX_GUIS, sizeof(Gui), CE_ALIGNOF(Gui))
{
}

//-----------------------------------------------------------------------------
RenderWorld::~RenderWorld()
{
}

//-----------------------------------------------------------------------------
MeshId RenderWorld::create_mesh(MeshResource* mr, SceneGraph& sg, int32_t node)
{
	Mesh* mesh = CE_NEW(m_mesh_pool, Mesh)(sg, node, mr);
	return id_array::create(m_mesh, mesh);
}

//-----------------------------------------------------------------------------
void RenderWorld::destroy_mesh(MeshId id)
{
	Mesh* mesh = id_array::get(m_mesh, id);
	CE_DELETE(m_mesh_pool, mesh);
	id_array::destroy(m_mesh, id);
}

//-----------------------------------------------------------------------------
Mesh* RenderWorld::get_mesh(MeshId mesh)
{
	return id_array::get(m_mesh, mesh);
}

//-----------------------------------------------------------------------------
SpriteId RenderWorld::create_sprite(SpriteResource* sr, SceneGraph& sg, int32_t node)
{
	Sprite* sprite = CE_NEW(m_sprite_pool, Sprite)(*this, sg, node, sr);
	return id_array::create(m_sprite, sprite);
}

//-----------------------------------------------------------------------------
void RenderWorld::destroy_sprite(SpriteId id)
{
	CE_DELETE(m_sprite_pool, id_array::get(m_sprite, id));
	id_array::destroy(m_sprite, id);
}

//-----------------------------------------------------------------------------
Sprite*	RenderWorld::get_sprite(SpriteId id)
{
	return id_array::get(m_sprite, id);
}

//-----------------------------------------------------------------------------
GuiId RenderWorld::create_gui(uint16_t width, uint16_t height, const char* material)
{
	Gui* gui = CE_NEW(m_gui_pool, Gui)(width, height, material);
	GuiId id = id_array::create(m_guis, gui);
	gui->set_id(id);
	return id;
}

//-----------------------------------------------------------------------------
void RenderWorld::destroy_gui(GuiId id)
{
	CE_DELETE(m_gui_pool, id_array::get(m_guis, id));
	id_array::destroy(m_guis, id);
}

//-----------------------------------------------------------------------------
Gui* RenderWorld::get_gui(GuiId id)
{
	return id_array::get(m_guis, id);
}

//-----------------------------------------------------------------------------
void RenderWorld::update(const Matrix4x4& view, const Matrix4x4& projection, uint16_t x, uint16_t y, uint16_t width, uint16_t height, float dt)
{
	bgfx::reset(width, height, BGFX_RESET_VSYNC);

	// Enable debug text.
	bgfx::setDebug(BGFX_DEBUG_TEXT);

	// Set view 0 clear state.
	bgfx::setViewClear(0
		, BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT
		, 0x353839FF
		, 1.0f
		, 0
		);

	// Set view and projection matrix for view 0.
	bgfx::setViewTransform(0, matrix4x4::to_float_ptr(view), matrix4x4::to_float_ptr(projection));
	bgfx::setViewRect(0, 0, 0, width, height);

	// This dummy draw call is here to make sure that view 0 is cleared
	// if no other draw calls are submitted to view 0.
	bgfx::submit(0);

	// Use debug font to print information about this example.
	bgfx::dbgTextClear();
	bgfx::dbgTextPrintf(0, 2, 0x6f, "dt = %4.7f", dt);

	// Draw all sprites
	for (uint32_t s = 0; s < id_array::size(m_sprite); s++)
	{
		m_sprite[s]->render();
	}

	// Advance to next frame. Rendering thread will be kicked to
	// process submitted rendering primitives.
	bgfx::frame();
}

} // namespace crown
<|endoftext|>


<commit_before>#include <iostream>
#include <stdint.h>
#include <map>
#include <vector>
#include <string>
#include <sys/stat.h>

#include "boost/program_options.hpp"
#include "api/BamReader.h"
#include "utils/bamtools_pileup_engine.h"
#include "utils/bamtools_fasta.h"

#include "model.h"
#include "parsers.h"

using namespace std;
using namespace BamTools;

class VariantVisitor : public ReadDataVisitor{
    public:
        VariantVisitor(const RefVector& bam_references,
                       Fasta& idx_ref,
                       ostream *out_stream,
                       SampleMap& samples,
                       const ModelParams& p,
                       BamAlignment& ali,
                       int qual_cut,
                       int mapping_cut,
                       double prob_cut,
                       MutationMatrix prob_paths_m,
                       MutationMatrix prob_paths_nm):

        ReadDataVisitor(bam_references, idx_ref, samples, p, ali, qual_cut, mapping_cut),
                        m_ostream(out_stream), m_prob_cut(prob_cut),
                        m_prob_paths_m(prob_paths_m), m_prob_paths_nm(prob_paths_nm)
                        {}

        ~VariantVisitor(void) { }
    public:
         void Visit(const PileupPosition& pileupData) {
            if (GatherReadData(pileupData) ){
                double prob = TetMAProbability(m_params, site_data, m_prob_paths_m, m_prob_paths_nm);
                if(prob >= m_prob_cut){
                    double prob_one = TetMAProbOneMutation(m_params, site_data, m_prob_paths_m, m_prob_paths_nm);
                         *m_ostream << m_bam_references[pileupData.RefId].RefName << '\t'
                                    << pileupData.Position << '\t'
                                    << current_base << '\t'
                                    << prob << '\t'
                                    << prob_one << '\t'
                                    << endl;
                }
            }
        }
    private:
        MutationMatrix m_prob_paths_m;
        MutationMatrix m_prob_paths_nm;
        ostream* m_ostream;
        double m_prob_cut;

};

int main(int argc, char** argv){

    namespace po = boost::program_options;
    string ref_file;
    string config_path;
    string anc_tag;
    po::options_description cmd("Command line options");
    cmd.add_options()
        ("help,h", "Print a help message")
        ("bam,b", po::value<string>()->required(), "Path to BAM file")
        ("bam-index,x", po::value<string>()->default_value(""), "Path to BAM index, (defalult is <bam_path>.bai")
        ("reference,r", po::value<string>(&ref_file)->required(),  "Path to reference genome")
        ("ancestor,a", po::value<string>(&anc_tag), "Ancestor RG sample ID")
        ("sample-name,s", po::value<vector <string> >()->required(), "Sample tags to include")
        ("qual,q", po::value<int>()->default_value(13),
                   "Base quality cuttoff")

        ("mapping-qual,m", po::value<int>()->default_value(13),
                    "Mapping quality cuttoff")

        ("prob,p", po::value<double>()->default_value(0.1),
                   "Mutaton probability cut-off")
        ("out,o", po::value<string>()->default_value("acuMUlate_result.tsv"),
                    "Out file name")
        ("intervals,i", po::value<string>(), "Path to bed file")
        ("config,c", po::value<string>(), "Path to config file")
        ("theta", po::value<double>()->required(), "theta")
        ("nfreqs", po::value<vector<double> >()->multitoken(), "")
        ("mu", po::value<double>()->required(), "")
        ("seq-error", po::value<double>()->required(), "")
        ("ploidy-ancestor", po::value<int>()->default_value(2), "")
        ("ploidy-descendant", po::value<int>()->default_value(2), "")
        ("phi-haploid",     po::value<double>()->required(), "")
        ("phi-diploid",     po::value<double>()->required(), "");
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, cmd), vm);

    if (vm.count("help")){
        cout << cmd << endl;
        return 0;
    }

    if (vm.count("config")){
        ifstream config_stream (vm["config"].as<string>());
        po::store(po::parse_config_file(config_stream, cmd, false), vm);
    }

    vm.notify();
    ModelParams params = {
        vm["theta"].as<double>(),
        vm["nfreqs"].as<vector< double> >(),
        vm["mu"].as<double>(),
        vm["seq-error"].as<double>(),
        vm["phi-haploid"].as<double>(),
        vm["phi-diploid"].as<double>(),
        vm["ploidy-ancestor"].as<int>(),
        vm["ploidy-descendant"].as<int>()
    };
    string bam_path = vm["bam"].as<string>();
    string index_path = vm["bam-index"].as<string>();
    if(index_path == ""){
        index_path = bam_path + ".bai";
    }

    ofstream result_stream (vm["out"].as<string>());
    // Start setiing up files
    //TODO: check sucsess of all these opens/reads:

    BamReader experiment;
    experiment.Open(bam_path);
    experiment.OpenIndex(index_path);
    RefVector references = experiment.GetReferenceData();
    SamHeader header = experiment.GetHeader();

    //Fasta reference
    Fasta reference_genome; // BamTools::Fasta
    struct stat file_info;
    string faidx_path = ref_file + ".fai";
    if (stat(faidx_path.c_str(), &file_info) != 0){
        reference_genome.Open(ref_file);
        reference_genome.CreateIndex(faidx_path);
    }
    reference_genome.Open(ref_file, faidx_path);

    // Map readgroups to samples
    // First check it we want to use a given sample
    // map all 'keeper' sample names to an index for ReadDataVectors use
    // (unsigned) -1 as a "missing" code
    //
    SampleMap name_map;
    vector<string> keepers =  vm["sample-name"].as< vector<string> >();
    uint16_t sindex = 1;
    bool ancestor_in_BAM = false;
    for(auto it = header.ReadGroups.Begin(); it!= header.ReadGroups.End(); it++){
        if(it->HasSample()){
            if (find(keepers.begin(), keepers.end(), it->Sample) == keepers.end()){
                if(it->Sample == anc_tag ){
                      name_map[it->Sample] = 0;
                      ancestor_in_BAM = true;
                } else {
                    name_map[it->Sample] = std::numeric_limits<uint32_t>::max()  ;
                    cerr << "Warning: excluding data from '" << it->Sample <<
                         "' which is included in the BAM file but not the list of included samples" << endl;
                }
            }else {
                auto s  = name_map.find(it->Sample);
                if( s == name_map.end()){
                    name_map[it->Sample] = sindex;
                    sindex += 1;
                }
            }
        }
    }
    if(!ancestor_in_BAM){
        cerr << "Error: No data for ancestral sample '" << anc_tag <<
            "' in the specifified BAM file. Check the sample tags match" << endl;
        exit(1);
    }
    // And now, go back over the read groups to map RG:sample index
    SampleMap samples;
    for(auto it = header.ReadGroups.Begin(); it!= header.ReadGroups.End(); it++){
        if(it->HasSample()){
            samples[it->ID] = name_map[it->Sample];
        }
    }

    PileupEngine pileup;
    BamAlignment ali;

    MutationMatrix mt = MutationAccumulation(params, true);
    MutationMatrix m = MutationAccumulation(params, false);
    MutationMatrix nm = m - mt;

    VariantVisitor *v = new VariantVisitor(
            references,
            reference_genome,
            &result_stream,
//            vm["sample-name"].as<vector< string> >(),
            samples,
            params,
            ali,
            vm["qual"].as<int>(),
            vm["mapping-qual"].as<int>(),
            vm["prob"].as<double>(),
            m, nm
        );
    pileup.AddVisitor(v);

    if (vm.count("intervals")){
        BedFile bed (vm["intervals"].as<string>());
        BedInterval region;
        while(bed.get_interval(region) == 0){
            int ref_id = experiment.GetReferenceID(region.chr);
            experiment.SetRegion(ref_id, region.start, ref_id, region.end);
            while( experiment.GetNextAlignment(ali) ){
                pileup.AddAlignment(ali);
            }
        }
    }
    else{
        while( experiment.GetNextAlignment(ali)){
            pileup.AddAlignment(ali);
        }
    }
    pileup.Flush();
    return 0;
}

<commit_msg>rename mutation matrices in VarVisitor for #5<commit_after>#include <iostream>
#include <stdint.h>
#include <map>
#include <vector>
#include <string>
#include <sys/stat.h>

#include "boost/program_options.hpp"
#include "api/BamReader.h"
#include "utils/bamtools_pileup_engine.h"
#include "utils/bamtools_fasta.h"

#include "model.h"
#include "parsers.h"

using namespace std;
using namespace BamTools;

class VariantVisitor : public ReadDataVisitor{
    public:
        VariantVisitor(const RefVector& bam_references,
                       Fasta& idx_ref,
                       ostream *out_stream,
                       SampleMap& samples,
                       const ModelParams& p,
                       BamAlignment& ali,
                       int qual_cut,
                       int mapping_cut,
                       double prob_cut,
                       MutationMatrix mut_paths,
                       MutationMatrix nomut_paths):

        ReadDataVisitor(bam_references, idx_ref, samples, p, ali, qual_cut, mapping_cut),
                        m_ostream(out_stream), m_prob_cut(prob_cut),
                        m_mut_paths(mut_paths), m_nomut_paths(nomut_paths)
                        {}

        ~VariantVisitor(void) { }
    public:
         void Visit(const PileupPosition& pileupData) {
            if (GatherReadData(pileupData) ){
                double prob = TetMAProbability(m_params, site_data, m_mut_paths, m_nomut_paths);
                if(prob >= m_prob_cut){
                    double prob_one = TetMAProbOneMutation(m_params, site_data, m_mut_paths, m_nomut_paths);
                         *m_ostream << m_bam_references[pileupData.RefId].RefName << '\t'
                                    << pileupData.Position << '\t'
                                    << current_base << '\t'
                                    << prob << '\t'
                                    << prob_one << '\t'
                                    << endl;
                }
            }
        }
    private:
        MutationMatrix m_mut_paths;
        MutationMatrix m_nomut_paths;
        ostream* m_ostream;
        double m_prob_cut;

};

int main(int argc, char** argv){

    namespace po = boost::program_options;
    string ref_file;
    string config_path;
    string anc_tag;
    po::options_description cmd("Command line options");
    cmd.add_options()
        ("help,h", "Print a help message")
        ("bam,b", po::value<string>()->required(), "Path to BAM file")
        ("bam-index,x", po::value<string>()->default_value(""), "Path to BAM index, (defalult is <bam_path>.bai")
        ("reference,r", po::value<string>(&ref_file)->required(),  "Path to reference genome")
        ("ancestor,a", po::value<string>(&anc_tag), "Ancestor RG sample ID")
        ("sample-name,s", po::value<vector <string> >()->required(), "Sample tags to include")
        ("qual,q", po::value<int>()->default_value(13),
                   "Base quality cuttoff")

        ("mapping-qual,m", po::value<int>()->default_value(13),
                    "Mapping quality cuttoff")

        ("prob,p", po::value<double>()->default_value(0.1),
                   "Mutaton probability cut-off")
        ("out,o", po::value<string>()->default_value("acuMUlate_result.tsv"),
                    "Out file name")
        ("intervals,i", po::value<string>(), "Path to bed file")
        ("config,c", po::value<string>(), "Path to config file")
        ("theta", po::value<double>()->required(), "theta")
        ("nfreqs", po::value<vector<double> >()->multitoken(), "")
        ("mu", po::value<double>()->required(), "")
        ("seq-error", po::value<double>()->required(), "")
        ("ploidy-ancestor", po::value<int>()->default_value(2), "")
        ("ploidy-descendant", po::value<int>()->default_value(2), "")
        ("phi-haploid",     po::value<double>()->required(), "")
        ("phi-diploid",     po::value<double>()->required(), "");
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, cmd), vm);

    if (vm.count("help")){
        cout << cmd << endl;
        return 0;
    }

    if (vm.count("config")){
        ifstream config_stream (vm["config"].as<string>());
        po::store(po::parse_config_file(config_stream, cmd, false), vm);
    }

    vm.notify();
    ModelParams params = {
        vm["theta"].as<double>(),
        vm["nfreqs"].as<vector< double> >(),
        vm["mu"].as<double>(),
        vm["seq-error"].as<double>(),
        vm["phi-haploid"].as<double>(),
        vm["phi-diploid"].as<double>(),
        vm["ploidy-ancestor"].as<int>(),
        vm["ploidy-descendant"].as<int>()
    };
    string bam_path = vm["bam"].as<string>();
    string index_path = vm["bam-index"].as<string>();
    if(index_path == ""){
        index_path = bam_path + ".bai";
    }

    ofstream result_stream (vm["out"].as<string>());
    // Start setiing up files
    //TODO: check sucsess of all these opens/reads:

    BamReader experiment;
    experiment.Open(bam_path);
    experiment.OpenIndex(index_path);
    RefVector references = experiment.GetReferenceData();
    SamHeader header = experiment.GetHeader();

    //Fasta reference
    Fasta reference_genome; // BamTools::Fasta
    struct stat file_info;
    string faidx_path = ref_file + ".fai";
    if (stat(faidx_path.c_str(), &file_info) != 0){
        reference_genome.Open(ref_file);
        reference_genome.CreateIndex(faidx_path);
    }
    reference_genome.Open(ref_file, faidx_path);

    // Map readgroups to samples
    // First check it we want to use a given sample
    // map all 'keeper' sample names to an index for ReadDataVectors use
    // (unsigned) -1 as a "missing" code
    //
    SampleMap name_map;
    vector<string> keepers =  vm["sample-name"].as< vector<string> >();
    uint16_t sindex = 1;
    bool ancestor_in_BAM = false;
    for(auto it = header.ReadGroups.Begin(); it!= header.ReadGroups.End(); it++){
        if(it->HasSample()){
            if (find(keepers.begin(), keepers.end(), it->Sample) == keepers.end()){
                if(it->Sample == anc_tag ){
                      name_map[it->Sample] = 0;
                      ancestor_in_BAM = true;
                } else {
                    name_map[it->Sample] = std::numeric_limits<uint32_t>::max()  ;
                    cerr << "Warning: excluding data from '" << it->Sample <<
                         "' which is included in the BAM file but not the list of included samples" << endl;
                }
            }else {
                auto s  = name_map.find(it->Sample);
                if( s == name_map.end()){
                    name_map[it->Sample] = sindex;
                    sindex += 1;
                }
            }
        }
    }
    if(!ancestor_in_BAM){
        cerr << "Error: No data for ancestral sample '" << anc_tag <<
            "' in the specifified BAM file. Check the sample tags match" << endl;
        exit(1);
    }
    // And now, go back over the read groups to map RG:sample index
    SampleMap samples;
    for(auto it = header.ReadGroups.Begin(); it!= header.ReadGroups.End(); it++){
        if(it->HasSample()){
            samples[it->ID] = name_map[it->Sample];
        }
    }

    PileupEngine pileup;
    BamAlignment ali;

    MutationMatrix mt = MutationAccumulation(params, true);
    MutationMatrix m = MutationAccumulation(params, false);
    MutationMatrix nm = m - mt;

    VariantVisitor *v = new VariantVisitor(
            references,
            reference_genome,
            &result_stream,
//            vm["sample-name"].as<vector< string> >(),
            samples,
            params,
            ali,
            vm["qual"].as<int>(),
            vm["mapping-qual"].as<int>(),
            vm["prob"].as<double>(),
            m, nm
        );
    pileup.AddVisitor(v);

    if (vm.count("intervals")){
        BedFile bed (vm["intervals"].as<string>());
        BedInterval region;
        while(bed.get_interval(region) == 0){
            int ref_id = experiment.GetReferenceID(region.chr);
            experiment.SetRegion(ref_id, region.start, ref_id, region.end);
            while( experiment.GetNextAlignment(ali) ){
                pileup.AddAlignment(ali);
            }
        }
    }
    else{
        while( experiment.GetNextAlignment(ali)){
            pileup.AddAlignment(ali);
        }
    }
    pileup.Flush();
    return 0;
}

<|endoftext|>


<commit_before>/**
 * \file
 * \brief Stack class implementation
 *
 * \author Copyright (C) 2014-2017 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "distortos/internal/scheduler/Stack.hpp"

#include "distortos/architecture/initializeStack.hpp"

#include "distortos/internal/memory/dummyDeleter.hpp"

#include <algorithm>

#if CONFIG_ARCHITECTURE_STACK_ALIGNMENT <= 0
#error "Stack alignment must be greater than 0!"
#endif	// CONFIG_ARCHITECTURE_STACK_ALIGNMENT <= 0

namespace distortos
{

namespace internal
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local objects
+---------------------------------------------------------------------------------------------------------------------*/

/// alignment of stack, bytes
constexpr size_t stackAlignment {CONFIG_ARCHITECTURE_STACK_ALIGNMENT};

/// sentinel used for stack usage/overflow detection
constexpr uint32_t stackSentinel {0xed419f25};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions' declarations
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Adjusts storage's address to suit architecture's alignment requirements.
 *
 * \param [in] storage is a pointer to stack's storage
 * \param [in] alignment is the required stack alignment, bytes
 *
 * \return adjusted storage's address
 */

void* adjustStorage(void* const storage, const size_t alignment)
{
	return reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(storage) + alignment - 1) / alignment * alignment);
}

/**
 * \brief Adjusts storage's size to suit architecture's alignment requirements.
 *
 * \param [in] storage is a pointer to stack's storage
 * \param [in] size is the size of stack's storage, bytes
 * \param [in] adjustedStorage is an adjusted storage's address
 * \param [in] alignment is the required stack alignment, bytes
 *
 * \return adjusted storage's size
 */

size_t adjustSize(void* const storage, const size_t size, void* const adjustedStorage, const size_t alignment)
{
	const auto storageEnd = reinterpret_cast<uintptr_t>(storage) + size;
	const auto adjustedStorageEnd = storageEnd / alignment * alignment;
	return adjustedStorageEnd - reinterpret_cast<decltype(adjustedStorageEnd)>(adjustedStorage);
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| public functions
+---------------------------------------------------------------------------------------------------------------------*/

Stack::Stack(StorageUniquePointer&& storageUniquePointer, const size_t size) :
		storageUniquePointer_{std::move(storageUniquePointer)},
		adjustedStorage_{adjustStorage(storageUniquePointer_.get(), stackAlignment)},
		adjustedSize_{adjustSize(storageUniquePointer_.get(), size, adjustedStorage_, stackAlignment)},
		stackPointer_{}
{

}

Stack::Stack(void* const storage, const size_t size) :
		storageUniquePointer_{storage, dummyDeleter<void*>},
		adjustedStorage_{storage},
		adjustedSize_{size},
		stackPointer_{}
{
	/// \todo implement minimal size check
}

Stack::~Stack()
{

}

bool Stack::checkStackGuard() const
{
	return std::all_of(static_cast<decltype(&stackSentinel)>(adjustedStorage_),
			static_cast<decltype(&stackSentinel)>(adjustedStorage_) + stackGuardSize_ / sizeof(stackSentinel),
			[](decltype(stackSentinel)& element) -> bool
			{
				return element == stackSentinel;
			});
}

size_t Stack::getHighWaterMark() const
{
	const auto begin =
			static_cast<decltype(&stackSentinel)>(adjustedStorage_) + stackGuardSize_ / sizeof(stackSentinel);
	const auto end = static_cast<decltype(&stackSentinel)>(adjustedStorage_) + adjustedSize_ / sizeof(stackSentinel);
	const auto usedElement = std::find_if_not(begin, end,
			[](decltype(stackSentinel)& element) -> bool
			{
				return element == stackSentinel;
			});
	return (end - usedElement) * sizeof(*begin);
}

int Stack::initialize(Thread& thread, void (& run)(Thread&), void (* const preTerminationHook)(Thread&),
			void (& terminationHook)(Thread&))
{
	std::fill_n(static_cast<std::decay<decltype(stackSentinel)>::type*>(adjustedStorage_),
			adjustedSize_ / sizeof(stackSentinel), stackSentinel);
	int ret;
	std::tie(ret, stackPointer_) =
			architecture::initializeStack(static_cast<uint8_t*>(adjustedStorage_) + stackGuardSize_,
			adjustedSize_ > stackGuardSize_ ? adjustedSize_ - stackGuardSize_ : 0, thread, run, preTerminationHook,
			terminationHook);
	return ret;
}

}	// namespace internal

}	// namespace distortos
<commit_msg>Use Stack::getSize() in Stack::initialize()<commit_after>/**
 * \file
 * \brief Stack class implementation
 *
 * \author Copyright (C) 2014-2017 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "distortos/internal/scheduler/Stack.hpp"

#include "distortos/architecture/initializeStack.hpp"

#include "distortos/internal/memory/dummyDeleter.hpp"

#include <algorithm>

#if CONFIG_ARCHITECTURE_STACK_ALIGNMENT <= 0
#error "Stack alignment must be greater than 0!"
#endif	// CONFIG_ARCHITECTURE_STACK_ALIGNMENT <= 0

namespace distortos
{

namespace internal
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local objects
+---------------------------------------------------------------------------------------------------------------------*/

/// alignment of stack, bytes
constexpr size_t stackAlignment {CONFIG_ARCHITECTURE_STACK_ALIGNMENT};

/// sentinel used for stack usage/overflow detection
constexpr uint32_t stackSentinel {0xed419f25};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions' declarations
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Adjusts storage's address to suit architecture's alignment requirements.
 *
 * \param [in] storage is a pointer to stack's storage
 * \param [in] alignment is the required stack alignment, bytes
 *
 * \return adjusted storage's address
 */

void* adjustStorage(void* const storage, const size_t alignment)
{
	return reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(storage) + alignment - 1) / alignment * alignment);
}

/**
 * \brief Adjusts storage's size to suit architecture's alignment requirements.
 *
 * \param [in] storage is a pointer to stack's storage
 * \param [in] size is the size of stack's storage, bytes
 * \param [in] adjustedStorage is an adjusted storage's address
 * \param [in] alignment is the required stack alignment, bytes
 *
 * \return adjusted storage's size
 */

size_t adjustSize(void* const storage, const size_t size, void* const adjustedStorage, const size_t alignment)
{
	const auto storageEnd = reinterpret_cast<uintptr_t>(storage) + size;
	const auto adjustedStorageEnd = storageEnd / alignment * alignment;
	return adjustedStorageEnd - reinterpret_cast<decltype(adjustedStorageEnd)>(adjustedStorage);
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| public functions
+---------------------------------------------------------------------------------------------------------------------*/

Stack::Stack(StorageUniquePointer&& storageUniquePointer, const size_t size) :
		storageUniquePointer_{std::move(storageUniquePointer)},
		adjustedStorage_{adjustStorage(storageUniquePointer_.get(), stackAlignment)},
		adjustedSize_{adjustSize(storageUniquePointer_.get(), size, adjustedStorage_, stackAlignment)},
		stackPointer_{}
{

}

Stack::Stack(void* const storage, const size_t size) :
		storageUniquePointer_{storage, dummyDeleter<void*>},
		adjustedStorage_{storage},
		adjustedSize_{size},
		stackPointer_{}
{
	/// \todo implement minimal size check
}

Stack::~Stack()
{

}

bool Stack::checkStackGuard() const
{
	return std::all_of(static_cast<decltype(&stackSentinel)>(adjustedStorage_),
			static_cast<decltype(&stackSentinel)>(adjustedStorage_) + stackGuardSize_ / sizeof(stackSentinel),
			[](decltype(stackSentinel)& element) -> bool
			{
				return element == stackSentinel;
			});
}

size_t Stack::getHighWaterMark() const
{
	const auto begin =
			static_cast<decltype(&stackSentinel)>(adjustedStorage_) + stackGuardSize_ / sizeof(stackSentinel);
	const auto end = static_cast<decltype(&stackSentinel)>(adjustedStorage_) + adjustedSize_ / sizeof(stackSentinel);
	const auto usedElement = std::find_if_not(begin, end,
			[](decltype(stackSentinel)& element) -> bool
			{
				return element == stackSentinel;
			});
	return (end - usedElement) * sizeof(*begin);
}

int Stack::initialize(Thread& thread, void (& run)(Thread&), void (* const preTerminationHook)(Thread&),
			void (& terminationHook)(Thread&))
{
	std::fill_n(static_cast<std::decay<decltype(stackSentinel)>::type*>(adjustedStorage_),
			adjustedSize_ / sizeof(stackSentinel), stackSentinel);
	int ret;
	std::tie(ret, stackPointer_) =
			architecture::initializeStack(static_cast<uint8_t*>(adjustedStorage_) + stackGuardSize_, getSize(), thread,
			run, preTerminationHook, terminationHook);
	return ret;
}

}	// namespace internal

}	// namespace distortos
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010-2011 Dmitry Marakasov
 *
 * This file is part of glosm.
 *
 * glosm is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * glosm is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with glosm.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "GlosmViewer.hh"

#include <glosm/Math.hh>
#include <glosm/MercatorProjection.hh>
#include <glosm/SphericalProjection.hh>
#include <glosm/Timer.hh>
#include <glosm/CheckGL.hh>
#include <glosm/geomath.h>

#include <glosm/util/gl.h>

#include <getopt.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>

#include <cstdio>

GlosmViewer::GlosmViewer() : projection_(MercatorProjection()), viewer_(new FirstPersonViewer) {
	screenw_ = screenh_ = 1;
	nframes_ = 0;

	movementflags_ = 0;
	speed_ = 200.0f;
	lockheight_ = 0;

	drag_ = slow_ = fast_ = false;

#if defined(WITH_TOUCHPAD)
	mouse_capture_ = false;
#else
	mouse_capture_ = true;
#endif

	ground_shown_ = true;
	detail_shown_ = true;

	no_glew_check_ = false;
}

void GlosmViewer::Usage(const char* progname) {
	fprintf(stderr, "Usage: %s [-sf] file.osm\n", progname);
	exit(1);
}

void GlosmViewer::Init(int argc, char** argv) {
	/* argument parsing */
	int c;
	const char* progname = argv[0];
	while ((c = getopt(argc, argv, "st:")) != -1) {
		switch (c) {
		case 's': projection_ = SphericalProjection(); break;
		case 'f': no_glew_check_ = true; break;
		default:
			Usage(progname);
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1)
		Usage(progname);

	/* load data */
	fprintf(stderr, "Loading...\n");
	gettimeofday(&prevtime_, NULL);

	osm_datasource_.reset(new PreloadedXmlDatasource);

	osm_datasource_->Load(argv[0]);
	gettimeofday(&curtime_, NULL);

	fprintf(stderr, "Loaded XML in %.3f seconds\n", (float)(curtime_.tv_sec - prevtime_.tv_sec) + (float)(curtime_.tv_usec - prevtime_.tv_usec)/1000000.0f);
	prevtime_ = curtime_;
	fpstime_ = curtime_;
}

void GlosmViewer::InitGL() {
	ShowCursor(!mouse_capture_);

#if defined(WITH_GLEW)
	GLenum err = glewInit();
	if (err != GLEW_OK)
		throw Exception() << "Cannot init glew: " << glewGetErrorString(err);
	const char *gl_requirements = "GL_VERSION_1_5";
	if (!glewIsSupported(gl_requirements)) {
		Exception e;
		e << "Minimal OpenGL requirements (" << gl_requirements << ") not met, unable to continue";
		if (no_glew_check_)
			fprintf(stderr, "(ignored) %s\n", e.what());
		else
			throw e;
	}
#endif
	CheckGL();

	geometry_generator_.reset(new GeometryGenerator(*osm_datasource_));
	ground_layer_.reset(new GeometryLayer(projection_, *geometry_generator_));
	detail_layer_.reset(new GeometryLayer(projection_, *geometry_generator_));

	ground_layer_->SetLevel(9);
	ground_layer_->SetRange(1000000.0);
	ground_layer_->SetFlags(GeometryDatasource::GROUND);
	ground_layer_->SetHeightEffect(false);
	ground_layer_->SetSizeLimit(32*1024*1024);

	detail_layer_->SetLevel(12);
	detail_layer_->SetRange(10000.0);
	detail_layer_->SetFlags(GeometryDatasource::DETAIL);
	detail_layer_->SetHeightEffect(true);
	detail_layer_->SetSizeLimit(32*1024*1024);

	int height = fabs((float)geometry_generator_->GetBBox().top - (float)geometry_generator_->GetBBox().bottom) / GEOM_LONSPAN * WGS84_EARTH_EQ_LENGTH * GEOM_UNITSINMETER / 10.0;
	viewer_->SetPos(Vector3i(geometry_generator_->GetCenter(), height));
#if defined(WITH_TOUCHPAD)
	lockheight_ = height;
#endif
	viewer_->SetRotation(0, -M_PI_4);
}

void GlosmViewer::Render() {
	/* update scene */
	gettimeofday(&curtime_, NULL);
	float dt = (float)(curtime_.tv_sec - prevtime_.tv_sec) + (float)(curtime_.tv_usec - prevtime_.tv_usec)/1000000.0f;

	/* render frame */
	glClearColor(0.5, 0.5, 0.5, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (ground_shown_) {
		ground_layer_->GarbageCollect();
		ground_layer_->LoadLocality(*viewer_);
		ground_layer_->Render(*viewer_);
	}

	if (detail_shown_) {
		detail_layer_->GarbageCollect();
		detail_layer_->LoadLocality(*viewer_);
		detail_layer_->Render(*viewer_);
	}

	glFlush();
	Flip();

	/* movement */
	if (movementflags_) {
		float myspeed = speed_;
		float height = viewer_->MutablePos().z / GEOM_UNITSINMETER;

		/* don't scale down under 100 meters */
		if (height > 100.0)
			myspeed *= height / 100.0;

		if (fast_)
			myspeed *= 5.0;
		if (slow_)
			myspeed /= 5.0;

		viewer_->Move(movementflags_, myspeed, dt);
	}
	if (lockheight_ != 0)
		viewer_->MutablePos().z = lockheight_;

	/* update FPS */
	float fpst = (float)(curtime_.tv_sec - fpstime_.tv_sec) + (float)(curtime_.tv_usec - fpstime_.tv_usec)/1000000.0f;

	if (fpst > 10.0) {
		fprintf(stderr, "FPS: %.3f\n", (float)nframes_/fpst);
		fpstime_ = curtime_;
		nframes_ = 0;
	}

	prevtime_ = curtime_;
	nframes_++;

	/* frame limiter */
	usleep(10000);
}

void GlosmViewer::Resize(int w, int h) {
	if (w <= 0)
		w = 1;
	if (h <= 0)
		h = 1;

	screenw_ = w;
	screenh_ = h;

	float wanted_fov = 70.0f/180.0f*M_PI;
	float wanted_aspect = 4.0f/3.0f;

	float fov, aspect;

	if ((float)w/(float)h > wanted_aspect) { // wider than wanted
		fov = wanted_fov;
	} else { // narrower than wanted
		float wanted_h = (float)w / wanted_aspect;
		fov = 2.0f * atanf((float)h / wanted_h * tanf(wanted_fov/2.0f));
	}
	fov = wanted_fov;
	aspect = (float)w/(float)h;

	glViewport(0, 0, w, h);

	viewer_->SetFov(fov);
	viewer_->SetAspect(aspect);

	WarpCursor(w/2, h/2);
}

void GlosmViewer::KeyDown(int key) {
	switch (key) {
	case 27: case 'q':
		exit(0);
		break;
	case 'w': case KEY_UP:
		movementflags_ |= FirstPersonViewer::FORWARD;
		break;
	case 's': case KEY_DOWN:
		movementflags_ |= FirstPersonViewer::BACKWARD;
		break;
	case 'a': case KEY_LEFT:
		movementflags_ |= FirstPersonViewer::LEFT;
		break;
	case 'd': case KEY_RIGHT:
		movementflags_ |= FirstPersonViewer::RIGHT;
		break;
	case 'c':
		movementflags_ |= FirstPersonViewer::LOWER;
		break;
	case ' ':
		movementflags_ |= FirstPersonViewer::HIGHER;
		break;
	case 'l':
		lockheight_ = (lockheight_ == 0 ? viewer_->MutablePos().z : 0);
		break;
	case 'h':
		lockheight_ = (lockheight_ == 0 ? 1.75 * GEOM_UNITSINMETER : 0);
		break;
	case '+':
		speed_ *= 5.0f;
		break;
	case '-':
		speed_ /= 5.0f;
		break;
	case '1':
		ground_shown_ = !ground_shown_;
		break;
	case '2':
		detail_shown_ = !detail_shown_;
		break;
	case KEY_SHIFT:
		fast_ = true;
		break;
	case KEY_CTRL:
		slow_ = true;
		break;
	default:
		break;
	}
}

void GlosmViewer::KeyUp(int key) {
	switch (key) {
	case 'w': case KEY_UP:
		movementflags_ &= ~FirstPersonViewer::FORWARD;
		break;
	case 's': case KEY_DOWN:
		movementflags_ &= ~FirstPersonViewer::BACKWARD;
		break;
	case 'a': case KEY_LEFT:
		movementflags_ &= ~FirstPersonViewer::LEFT;
		break;
	case 'd': case KEY_RIGHT:
		movementflags_ &= ~FirstPersonViewer::RIGHT;
		break;
	case 'c':
		movementflags_ &= ~FirstPersonViewer::LOWER;
		break;
	case ' ':
		movementflags_ &= ~FirstPersonViewer::HIGHER;
		break;
	case KEY_SHIFT:
		fast_ = false;
		break;
	case KEY_CTRL:
		slow_ = false;
		break;
	default:
		break;
	}
}

void GlosmViewer::MouseMove(int x, int y) {
	if (drag_) {
		int dx = x - drag_start_pos_.x;
		int dy = y - drag_start_pos_.y;

		float yawdelta = -(float)dx / (float)screenw_ * viewer_->GetFov() * viewer_->GetAspect();
		float pitchdelta = (float)dy / (float)screenh_ * viewer_->GetFov();

		viewer_->SetRotation(drag_start_yaw_ + yawdelta, drag_start_pitch_ + pitchdelta);
	}

	if (mouse_capture_) {
		int dx = x - screenw_/2;
		int dy = y - screenh_/2;

		float yawdelta = (float)dx / 500.0;
		float pitchdelta = -(float)dy / 500.0;

		viewer_->Rotate(yawdelta, pitchdelta, 1.0);

		if (dx != 0 || dy != 0)
			WarpCursor(screenw_/2, screenh_/2);
	}
}

void GlosmViewer::MouseButton(int button, bool pressed, int x, int y) {
	if (button == BUTTON_RIGHT && pressed) {
		mouse_capture_ = !mouse_capture_;
		ShowCursor(!mouse_capture_);
	}

	if (!mouse_capture_ && button == BUTTON_LEFT) {
		drag_ = pressed;
		if (pressed) {
			drag_start_pos_.x = x;
			drag_start_pos_.y = y;
			drag_start_yaw_ = viewer_->GetYaw();
			drag_start_pitch_ = viewer_->GetPitch();
		}
	}
}
<commit_msg>Fix getopt for viewer<commit_after>/*
 * Copyright (C) 2010-2011 Dmitry Marakasov
 *
 * This file is part of glosm.
 *
 * glosm is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * glosm is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with glosm.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "GlosmViewer.hh"

#include <glosm/Math.hh>
#include <glosm/MercatorProjection.hh>
#include <glosm/SphericalProjection.hh>
#include <glosm/Timer.hh>
#include <glosm/CheckGL.hh>
#include <glosm/geomath.h>

#include <glosm/util/gl.h>

#include <getopt.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>

#include <cstdio>

GlosmViewer::GlosmViewer() : projection_(MercatorProjection()), viewer_(new FirstPersonViewer) {
	screenw_ = screenh_ = 1;
	nframes_ = 0;

	movementflags_ = 0;
	speed_ = 200.0f;
	lockheight_ = 0;

	drag_ = slow_ = fast_ = false;

#if defined(WITH_TOUCHPAD)
	mouse_capture_ = false;
#else
	mouse_capture_ = true;
#endif

	ground_shown_ = true;
	detail_shown_ = true;

	no_glew_check_ = false;
}

void GlosmViewer::Usage(const char* progname) {
	fprintf(stderr, "Usage: %s [-sf] file.osm\n", progname);
	exit(1);
}

void GlosmViewer::Init(int argc, char** argv) {
	/* argument parsing */
	int c;
	const char* progname = argv[0];
	while ((c = getopt(argc, argv, "sf")) != -1) {
		switch (c) {
		case 's': projection_ = SphericalProjection(); break;
		case 'f': no_glew_check_ = true; break;
		default:
			Usage(progname);
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1)
		Usage(progname);

	/* load data */
	fprintf(stderr, "Loading...\n");
	gettimeofday(&prevtime_, NULL);

	osm_datasource_.reset(new PreloadedXmlDatasource);

	osm_datasource_->Load(argv[0]);
	gettimeofday(&curtime_, NULL);

	fprintf(stderr, "Loaded XML in %.3f seconds\n", (float)(curtime_.tv_sec - prevtime_.tv_sec) + (float)(curtime_.tv_usec - prevtime_.tv_usec)/1000000.0f);
	prevtime_ = curtime_;
	fpstime_ = curtime_;
}

void GlosmViewer::InitGL() {
	ShowCursor(!mouse_capture_);

#if defined(WITH_GLEW)
	GLenum err = glewInit();
	if (err != GLEW_OK)
		throw Exception() << "Cannot init glew: " << glewGetErrorString(err);
	const char *gl_requirements = "GL_VERSION_1_5";
	if (!glewIsSupported(gl_requirements)) {
		Exception e;
		e << "Minimal OpenGL requirements (" << gl_requirements << ") not met, unable to continue";
		if (no_glew_check_)
			fprintf(stderr, "(ignored) %s\n", e.what());
		else
			throw e;
	}
#endif
	CheckGL();

	geometry_generator_.reset(new GeometryGenerator(*osm_datasource_));
	ground_layer_.reset(new GeometryLayer(projection_, *geometry_generator_));
	detail_layer_.reset(new GeometryLayer(projection_, *geometry_generator_));

	ground_layer_->SetLevel(9);
	ground_layer_->SetRange(1000000.0);
	ground_layer_->SetFlags(GeometryDatasource::GROUND);
	ground_layer_->SetHeightEffect(false);
	ground_layer_->SetSizeLimit(32*1024*1024);

	detail_layer_->SetLevel(12);
	detail_layer_->SetRange(10000.0);
	detail_layer_->SetFlags(GeometryDatasource::DETAIL);
	detail_layer_->SetHeightEffect(true);
	detail_layer_->SetSizeLimit(32*1024*1024);

	int height = fabs((float)geometry_generator_->GetBBox().top - (float)geometry_generator_->GetBBox().bottom) / GEOM_LONSPAN * WGS84_EARTH_EQ_LENGTH * GEOM_UNITSINMETER / 10.0;
	viewer_->SetPos(Vector3i(geometry_generator_->GetCenter(), height));
#if defined(WITH_TOUCHPAD)
	lockheight_ = height;
#endif
	viewer_->SetRotation(0, -M_PI_4);
}

void GlosmViewer::Render() {
	/* update scene */
	gettimeofday(&curtime_, NULL);
	float dt = (float)(curtime_.tv_sec - prevtime_.tv_sec) + (float)(curtime_.tv_usec - prevtime_.tv_usec)/1000000.0f;

	/* render frame */
	glClearColor(0.5, 0.5, 0.5, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (ground_shown_) {
		ground_layer_->GarbageCollect();
		ground_layer_->LoadLocality(*viewer_);
		ground_layer_->Render(*viewer_);
	}

	if (detail_shown_) {
		detail_layer_->GarbageCollect();
		detail_layer_->LoadLocality(*viewer_);
		detail_layer_->Render(*viewer_);
	}

	glFlush();
	Flip();

	/* movement */
	if (movementflags_) {
		float myspeed = speed_;
		float height = viewer_->MutablePos().z / GEOM_UNITSINMETER;

		/* don't scale down under 100 meters */
		if (height > 100.0)
			myspeed *= height / 100.0;

		if (fast_)
			myspeed *= 5.0;
		if (slow_)
			myspeed /= 5.0;

		viewer_->Move(movementflags_, myspeed, dt);
	}
	if (lockheight_ != 0)
		viewer_->MutablePos().z = lockheight_;

	/* update FPS */
	float fpst = (float)(curtime_.tv_sec - fpstime_.tv_sec) + (float)(curtime_.tv_usec - fpstime_.tv_usec)/1000000.0f;

	if (fpst > 10.0) {
		fprintf(stderr, "FPS: %.3f\n", (float)nframes_/fpst);
		fpstime_ = curtime_;
		nframes_ = 0;
	}

	prevtime_ = curtime_;
	nframes_++;

	/* frame limiter */
	usleep(10000);
}

void GlosmViewer::Resize(int w, int h) {
	if (w <= 0)
		w = 1;
	if (h <= 0)
		h = 1;

	screenw_ = w;
	screenh_ = h;

	float wanted_fov = 70.0f/180.0f*M_PI;
	float wanted_aspect = 4.0f/3.0f;

	float fov, aspect;

	if ((float)w/(float)h > wanted_aspect) { // wider than wanted
		fov = wanted_fov;
	} else { // narrower than wanted
		float wanted_h = (float)w / wanted_aspect;
		fov = 2.0f * atanf((float)h / wanted_h * tanf(wanted_fov/2.0f));
	}
	fov = wanted_fov;
	aspect = (float)w/(float)h;

	glViewport(0, 0, w, h);

	viewer_->SetFov(fov);
	viewer_->SetAspect(aspect);

	WarpCursor(w/2, h/2);
}

void GlosmViewer::KeyDown(int key) {
	switch (key) {
	case 27: case 'q':
		exit(0);
		break;
	case 'w': case KEY_UP:
		movementflags_ |= FirstPersonViewer::FORWARD;
		break;
	case 's': case KEY_DOWN:
		movementflags_ |= FirstPersonViewer::BACKWARD;
		break;
	case 'a': case KEY_LEFT:
		movementflags_ |= FirstPersonViewer::LEFT;
		break;
	case 'd': case KEY_RIGHT:
		movementflags_ |= FirstPersonViewer::RIGHT;
		break;
	case 'c':
		movementflags_ |= FirstPersonViewer::LOWER;
		break;
	case ' ':
		movementflags_ |= FirstPersonViewer::HIGHER;
		break;
	case 'l':
		lockheight_ = (lockheight_ == 0 ? viewer_->MutablePos().z : 0);
		break;
	case 'h':
		lockheight_ = (lockheight_ == 0 ? 1.75 * GEOM_UNITSINMETER : 0);
		break;
	case '+':
		speed_ *= 5.0f;
		break;
	case '-':
		speed_ /= 5.0f;
		break;
	case '1':
		ground_shown_ = !ground_shown_;
		break;
	case '2':
		detail_shown_ = !detail_shown_;
		break;
	case KEY_SHIFT:
		fast_ = true;
		break;
	case KEY_CTRL:
		slow_ = true;
		break;
	default:
		break;
	}
}

void GlosmViewer::KeyUp(int key) {
	switch (key) {
	case 'w': case KEY_UP:
		movementflags_ &= ~FirstPersonViewer::FORWARD;
		break;
	case 's': case KEY_DOWN:
		movementflags_ &= ~FirstPersonViewer::BACKWARD;
		break;
	case 'a': case KEY_LEFT:
		movementflags_ &= ~FirstPersonViewer::LEFT;
		break;
	case 'd': case KEY_RIGHT:
		movementflags_ &= ~FirstPersonViewer::RIGHT;
		break;
	case 'c':
		movementflags_ &= ~FirstPersonViewer::LOWER;
		break;
	case ' ':
		movementflags_ &= ~FirstPersonViewer::HIGHER;
		break;
	case KEY_SHIFT:
		fast_ = false;
		break;
	case KEY_CTRL:
		slow_ = false;
		break;
	default:
		break;
	}
}

void GlosmViewer::MouseMove(int x, int y) {
	if (drag_) {
		int dx = x - drag_start_pos_.x;
		int dy = y - drag_start_pos_.y;

		float yawdelta = -(float)dx / (float)screenw_ * viewer_->GetFov() * viewer_->GetAspect();
		float pitchdelta = (float)dy / (float)screenh_ * viewer_->GetFov();

		viewer_->SetRotation(drag_start_yaw_ + yawdelta, drag_start_pitch_ + pitchdelta);
	}

	if (mouse_capture_) {
		int dx = x - screenw_/2;
		int dy = y - screenh_/2;

		float yawdelta = (float)dx / 500.0;
		float pitchdelta = -(float)dy / 500.0;

		viewer_->Rotate(yawdelta, pitchdelta, 1.0);

		if (dx != 0 || dy != 0)
			WarpCursor(screenw_/2, screenh_/2);
	}
}

void GlosmViewer::MouseButton(int button, bool pressed, int x, int y) {
	if (button == BUTTON_RIGHT && pressed) {
		mouse_capture_ = !mouse_capture_;
		ShowCursor(!mouse_capture_);
	}

	if (!mouse_capture_ && button == BUTTON_LEFT) {
		drag_ = pressed;
		if (pressed) {
			drag_start_pos_.x = x;
			drag_start_pos_.y = y;
			drag_start_yaw_ = viewer_->GetYaw();
			drag_start_pitch_ = viewer_->GetPitch();
		}
	}
}
<|endoftext|>


<commit_before>/**
 * @file		sysmanager.cpp
 * @brief		COSSB system manager
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 7. 29
 * @details
 */

#include "manager.hpp"
#include "logger.hpp"
#include "interface/ilog.hpp"
#include "base/libadopter.hpp"

namespace cossb {
namespace manager {

system_manager::system_manager()
{

}

system_manager::~system_manager()
{
	cossb_component_manager->destroy();
	cossb_log->destroy();

	if(_log_adopter)	delete _log_adopter;
}

bool system_manager::setup(base::configreader* config)
{
	//1. load log library
	for(auto dep:*config->get_library()) {
		if(!dep->use.compare("log")) {
			_log_adopter = new base::libadopter<interface::ilog>(dep->sofile.c_str());
			cossb_log->adopt(_log_adopter->get_lib());
		}
	}

	//2. load dependent components
	for(auto dep:*config->get_dependency()) {
		if(dep->type==base::dependencyType::COMPONENT)
			cossb_component_manager->install(dep->name.c_str());
	}

	return true;
}

bool system_manager::is_setup() const
{
	return initialized;
}

} /* namespace manager */
} /* namespace cossb */
<commit_msg>add mdns adopter<commit_after>/**
 * @file		sysmanager.cpp
 * @brief		COSSB system manager
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 7. 29
 * @details
 */

#include "manager.hpp"
#include "logger.hpp"
#include "interface/ilog.hpp"
#include "base/libadopter.hpp"

namespace cossb {
namespace manager {

system_manager::system_manager()
{

}

system_manager::~system_manager()
{
	cossb_component_manager->destroy();
	cossb_log->destroy();

	if(_log_adopter)	delete _log_adopter;
	if(_mdns_adopter)	delete _mdns_adopter;
}

bool system_manager::setup(base::configreader* config)
{
	//1. load log library
	for(auto dep:*config->get_library()) {
		if(!dep->use.compare("log") && !dep->sofile.empty()) {
			_log_adopter = new base::libadopter<interface::ilog>(dep->sofile.c_str());
			cossb_log->adopt(_log_adopter->get_lib());
		}

		if(!dep->use.compare("mdns") && !dep->sofile.empty()) {
			_mdns_adopter = new base::libadopter<interface::isimpleservice>(dep->sofile.c_str());
		}
	}

	//2. load dependent components
	for(auto dep:*config->get_dependency()) {
		if(dep->type==base::dependencyType::COMPONENT)
			cossb_component_manager->install(dep->name.c_str());
	}

	return true;
}

bool system_manager::is_setup() const
{
	return initialized;
}

} /* namespace manager */
} /* namespace cossb */
<|endoftext|>