forked from mirror/openmw-tes3mp
Merge branch 'master' of https://github.com/zinnschlag/openmw into terraincollision
Conflicts: CMakeLists.txtactorid
commit
9612ce595b
@ -1,6 +0,0 @@
|
|||||||
[submodule "libs/mangle"]
|
|
||||||
path = libs/mangle
|
|
||||||
url = git://github.com/zinnschlag/mangle.git
|
|
||||||
[submodule "libs/openengine"]
|
|
||||||
path = libs/openengine
|
|
||||||
url = git://github.com/zinnschlag/OpenEngine
|
|
@ -1,10 +0,0 @@
|
|||||||
package "esmtool"
|
|
||||||
version "1.0"
|
|
||||||
purpose "Inspect and extract from Morrowind ES files (ESM, ESP, ESS)"
|
|
||||||
args "--unamed-opts=ES-FILE -F esmtool_cmd -G"
|
|
||||||
|
|
||||||
option "raw" r "Show an unformattet list of all records and subrecords" optional
|
|
||||||
option "quiet" q "Supress all record information. Useful for speed tests." optional
|
|
||||||
option "loadcells" C "Browse through contents of all cells." optional
|
|
||||||
|
|
||||||
text "\nIf no option is given, the default action is to parse all records in the archive and display diagnostic information."
|
|
File diff suppressed because it is too large
Load Diff
@ -1,179 +0,0 @@
|
|||||||
/** @file esmtool_cmd.h
|
|
||||||
* @brief The header file for the command line option parser
|
|
||||||
* generated by GNU Gengetopt version 2.22.2
|
|
||||||
* http://www.gnu.org/software/gengetopt.
|
|
||||||
* DO NOT modify this file, since it can be overwritten
|
|
||||||
* @author GNU Gengetopt by Lorenzo Bettini */
|
|
||||||
|
|
||||||
#ifndef ESMTOOL_CMD_H
|
|
||||||
#define ESMTOOL_CMD_H
|
|
||||||
|
|
||||||
/* If we use autoconf. */
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h> /* for FILE */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#ifndef CMDLINE_PARSER_PACKAGE
|
|
||||||
/** @brief the program name (used for printing errors) */
|
|
||||||
#define CMDLINE_PARSER_PACKAGE "esmtool"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CMDLINE_PARSER_PACKAGE_NAME
|
|
||||||
/** @brief the complete program name (used for help and version) */
|
|
||||||
#define CMDLINE_PARSER_PACKAGE_NAME "esmtool"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CMDLINE_PARSER_VERSION
|
|
||||||
/** @brief the program version */
|
|
||||||
#define CMDLINE_PARSER_VERSION "1.0"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @brief Where the command line options are stored */
|
|
||||||
struct gengetopt_args_info
|
|
||||||
{
|
|
||||||
const char *help_help; /**< @brief Print help and exit help description. */
|
|
||||||
const char *version_help; /**< @brief Print version and exit help description. */
|
|
||||||
const char *raw_help; /**< @brief Show an unformattet list of all records and subrecords help description. */
|
|
||||||
const char *quiet_help; /**< @brief Supress all record information. Useful for speed tests. help description. */
|
|
||||||
const char *loadcells_help; /**< @brief Browse through contents of all cells. help description. */
|
|
||||||
|
|
||||||
unsigned int help_given ; /**< @brief Whether help was given. */
|
|
||||||
unsigned int version_given ; /**< @brief Whether version was given. */
|
|
||||||
unsigned int raw_given ; /**< @brief Whether raw was given. */
|
|
||||||
unsigned int quiet_given ; /**< @brief Whether quiet was given. */
|
|
||||||
unsigned int loadcells_given ; /**< @brief Whether loadcells was given. */
|
|
||||||
|
|
||||||
char **inputs ; /**< @brief unamed options (options without names) */
|
|
||||||
unsigned inputs_num ; /**< @brief unamed options number */
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/** @brief The additional parameters to pass to parser functions */
|
|
||||||
struct cmdline_parser_params
|
|
||||||
{
|
|
||||||
int override; /**< @brief whether to override possibly already present options (default 0) */
|
|
||||||
int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
|
|
||||||
int check_required; /**< @brief whether to check that all required options were provided (default 1) */
|
|
||||||
int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
|
|
||||||
int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/** @brief the purpose string of the program */
|
|
||||||
extern const char *gengetopt_args_info_purpose;
|
|
||||||
/** @brief the usage string of the program */
|
|
||||||
extern const char *gengetopt_args_info_usage;
|
|
||||||
/** @brief all the lines making the help output */
|
|
||||||
extern const char *gengetopt_args_info_help[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The command line parser
|
|
||||||
* @param argc the number of command line options
|
|
||||||
* @param argv the command line options
|
|
||||||
* @param args_info the structure where option information will be stored
|
|
||||||
* @return 0 if everything went fine, NON 0 if an error took place
|
|
||||||
*/
|
|
||||||
int cmdline_parser (int argc, char * const *argv,
|
|
||||||
struct gengetopt_args_info *args_info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The command line parser (version with additional parameters - deprecated)
|
|
||||||
* @param argc the number of command line options
|
|
||||||
* @param argv the command line options
|
|
||||||
* @param args_info the structure where option information will be stored
|
|
||||||
* @param override whether to override possibly already present options
|
|
||||||
* @param initialize whether to initialize the option structure my_args_info
|
|
||||||
* @param check_required whether to check that all required options were provided
|
|
||||||
* @return 0 if everything went fine, NON 0 if an error took place
|
|
||||||
* @deprecated use cmdline_parser_ext() instead
|
|
||||||
*/
|
|
||||||
int cmdline_parser2 (int argc, char * const *argv,
|
|
||||||
struct gengetopt_args_info *args_info,
|
|
||||||
int override, int initialize, int check_required);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The command line parser (version with additional parameters)
|
|
||||||
* @param argc the number of command line options
|
|
||||||
* @param argv the command line options
|
|
||||||
* @param args_info the structure where option information will be stored
|
|
||||||
* @param params additional parameters for the parser
|
|
||||||
* @return 0 if everything went fine, NON 0 if an error took place
|
|
||||||
*/
|
|
||||||
int cmdline_parser_ext (int argc, char * const *argv,
|
|
||||||
struct gengetopt_args_info *args_info,
|
|
||||||
struct cmdline_parser_params *params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the contents of the option struct into an already open FILE stream.
|
|
||||||
* @param outfile the stream where to dump options
|
|
||||||
* @param args_info the option struct to dump
|
|
||||||
* @return 0 if everything went fine, NON 0 if an error took place
|
|
||||||
*/
|
|
||||||
int cmdline_parser_dump(FILE *outfile,
|
|
||||||
struct gengetopt_args_info *args_info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the contents of the option struct into a (text) file.
|
|
||||||
* This file can be read by the config file parser (if generated by gengetopt)
|
|
||||||
* @param filename the file where to save
|
|
||||||
* @param args_info the option struct to save
|
|
||||||
* @return 0 if everything went fine, NON 0 if an error took place
|
|
||||||
*/
|
|
||||||
int cmdline_parser_file_save(const char *filename,
|
|
||||||
struct gengetopt_args_info *args_info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print the help
|
|
||||||
*/
|
|
||||||
void cmdline_parser_print_help(void);
|
|
||||||
/**
|
|
||||||
* Print the version
|
|
||||||
*/
|
|
||||||
void cmdline_parser_print_version(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes all the fields a cmdline_parser_params structure
|
|
||||||
* to their default values
|
|
||||||
* @param params the structure to initialize
|
|
||||||
*/
|
|
||||||
void cmdline_parser_params_init(struct cmdline_parser_params *params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocates dynamically a cmdline_parser_params structure and initializes
|
|
||||||
* all its fields to their default values
|
|
||||||
* @return the created and initialized cmdline_parser_params structure
|
|
||||||
*/
|
|
||||||
struct cmdline_parser_params *cmdline_parser_params_create(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the passed gengetopt_args_info structure's fields
|
|
||||||
* (also set default values for options that have a default)
|
|
||||||
* @param args_info the structure to initialize
|
|
||||||
*/
|
|
||||||
void cmdline_parser_init (struct gengetopt_args_info *args_info);
|
|
||||||
/**
|
|
||||||
* Deallocates the string fields of the gengetopt_args_info structure
|
|
||||||
* (but does not deallocate the structure itself)
|
|
||||||
* @param args_info the structure to deallocate
|
|
||||||
*/
|
|
||||||
void cmdline_parser_free (struct gengetopt_args_info *args_info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks that all the required options were specified
|
|
||||||
* @param args_info the structure to check
|
|
||||||
* @param prog_name the name of the program that will be used to print
|
|
||||||
* possible errors
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
int cmdline_parser_required (struct gengetopt_args_info *args_info,
|
|
||||||
const char *prog_name);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
#endif /* ESMTOOL_CMD_H */
|
|
@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
#include "inventorystore.hpp"
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "class.hpp"
|
||||||
|
|
||||||
|
void MWWorld::InventoryStore::copySlots (const InventoryStore& store)
|
||||||
|
{
|
||||||
|
// some const-trickery, required because of a flaw in the handling of MW-references and the
|
||||||
|
// resulting workarounds
|
||||||
|
for (std::vector<ContainerStoreIterator>::const_iterator iter (
|
||||||
|
const_cast<InventoryStore&> (store).mSlots.begin());
|
||||||
|
iter!=const_cast<InventoryStore&> (store).mSlots.end(); ++iter)
|
||||||
|
{
|
||||||
|
std::size_t distance = std::distance (const_cast<InventoryStore&> (store).begin(), *iter);
|
||||||
|
|
||||||
|
ContainerStoreIterator slot = begin();
|
||||||
|
|
||||||
|
std::advance (slot, distance);
|
||||||
|
|
||||||
|
mSlots.push_back (slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::InventoryStore::InventoryStore()
|
||||||
|
{
|
||||||
|
for (int i=0; i<Slots; ++i)
|
||||||
|
mSlots.push_back (end());
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
||||||
|
: ContainerStore (store)
|
||||||
|
{
|
||||||
|
copySlots (store);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStore& store)
|
||||||
|
{
|
||||||
|
ContainerStore::operator= (store);
|
||||||
|
mSlots.clear();
|
||||||
|
copySlots (store);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& iterator)
|
||||||
|
{
|
||||||
|
if (slot<0 || slot>=static_cast<int> (mSlots.size()))
|
||||||
|
throw std::runtime_error ("slot number out of range");
|
||||||
|
|
||||||
|
if (iterator.getContainerStore()!=this)
|
||||||
|
throw std::runtime_error ("attempt to equip an item that is not in the inventory");
|
||||||
|
|
||||||
|
if (iterator!=end())
|
||||||
|
{
|
||||||
|
std::pair<std::vector<int>, bool> slots = Class::get (*iterator).getEquipmentSlots (*iterator);
|
||||||
|
|
||||||
|
if (std::find (slots.first.begin(), slots.first.end(), slot)==slots.first.end())
|
||||||
|
throw std::runtime_error ("invalid slot");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \todo restack item previously in this slot (if required)
|
||||||
|
|
||||||
|
/// \todo unstack item pointed to by iterator if required)
|
||||||
|
|
||||||
|
mSlots[slot] = iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot)
|
||||||
|
{
|
||||||
|
if (slot<0 || slot>=static_cast<int> (mSlots.size()))
|
||||||
|
throw std::runtime_error ("slot number out of range");
|
||||||
|
|
||||||
|
if (mSlots[slot]==end())
|
||||||
|
return end();
|
||||||
|
|
||||||
|
if (mSlots[slot]->getRefData().getCount()<1)
|
||||||
|
{
|
||||||
|
// object has been deleted
|
||||||
|
mSlots[slot] = end();
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mSlots[slot];
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef GAME_MWWORLD_INVENTORYSTORE_H
|
||||||
|
#define GAME_MWWORLD_INVENTORYSTORE_H
|
||||||
|
|
||||||
|
#include "containerstore.hpp"
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
///< \brief Variant of the ContainerStore for NPCs
|
||||||
|
class InventoryStore : public ContainerStore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const int Slot_Helmet = 0;
|
||||||
|
static const int Slot_Cuirass = 1;
|
||||||
|
static const int Slot_Greaves = 2;
|
||||||
|
static const int Slot_LeftPauldron = 3;
|
||||||
|
static const int Slot_RightPauldron = 4;
|
||||||
|
static const int Slot_LeftGauntlet = 5;
|
||||||
|
static const int Slot_RightGauntlet = 6;
|
||||||
|
static const int Slot_Boots = 7;
|
||||||
|
static const int Slot_Shirt = 8;
|
||||||
|
static const int Slot_Pants = 9;
|
||||||
|
static const int Slot_Skirt = 10;
|
||||||
|
static const int Slot_Robe = 11;
|
||||||
|
static const int Slot_LeftRing = 12;
|
||||||
|
static const int Slot_RightRing = 13;
|
||||||
|
static const int Slot_Amulet = 14;
|
||||||
|
static const int Slot_Belt = 15;
|
||||||
|
static const int Slot_CarriedRight = 16;
|
||||||
|
static const int Slot_CarriedLeft = 17;
|
||||||
|
static const int Slot_Ammunition = 18;
|
||||||
|
|
||||||
|
static const int Slots = 19;
|
||||||
|
|
||||||
|
static const int Slot_NoSlot = -1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
mutable std::vector<ContainerStoreIterator> mSlots;
|
||||||
|
|
||||||
|
void copySlots (const InventoryStore& store);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
InventoryStore();
|
||||||
|
|
||||||
|
InventoryStore (const InventoryStore& store);
|
||||||
|
|
||||||
|
InventoryStore& operator= (const InventoryStore& store);
|
||||||
|
|
||||||
|
void equip (int slot, const ContainerStoreIterator& iterator);
|
||||||
|
///< \note \a iteartor can be an end-iterator
|
||||||
|
|
||||||
|
ContainerStoreIterator getSlot (int slot);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,157 +0,0 @@
|
|||||||
#include "configurationmanager.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace Cfg
|
|
||||||
{
|
|
||||||
|
|
||||||
static const char* const openmwCfgFile = "openmw.cfg";
|
|
||||||
static const char* const ogreCfgFile = "ogre.cfg";
|
|
||||||
static const char* const pluginsCfgFile = "plugins.cfg";
|
|
||||||
|
|
||||||
|
|
||||||
ConfigurationManager::ConfigurationManager()
|
|
||||||
: mPath("openmw")
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* According to task #168 plugins.cfg file shall be located in global
|
|
||||||
* configuration path or in runtime configuration path.
|
|
||||||
*/
|
|
||||||
mPluginsCfgPath = mPath.getGlobalConfigPath() / pluginsCfgFile;
|
|
||||||
if (!boost::filesystem::is_regular_file(mPluginsCfgPath))
|
|
||||||
{
|
|
||||||
mPluginsCfgPath = mPath.getRuntimeConfigPath() / pluginsCfgFile;
|
|
||||||
if (!boost::filesystem::is_regular_file(mPluginsCfgPath))
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to find " << pluginsCfgFile << " file!" << std::endl;
|
|
||||||
mPluginsCfgPath.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* According to task #168 ogre.cfg file shall be located only
|
|
||||||
* in user configuration path.
|
|
||||||
*/
|
|
||||||
mOgreCfgPath = mPath.getLocalConfigPath() / ogreCfgFile;
|
|
||||||
|
|
||||||
mLogPath = mPath.getLocalConfigPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigurationManager::~ConfigurationManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables,
|
|
||||||
boost::program_options::options_description& description)
|
|
||||||
{
|
|
||||||
loadConfig(mPath.getLocalConfigPath(), variables, description);
|
|
||||||
boost::program_options::notify(variables);
|
|
||||||
loadConfig(mPath.getRuntimeConfigPath(), variables, description);
|
|
||||||
boost::program_options::notify(variables);
|
|
||||||
loadConfig(mPath.getGlobalConfigPath(), variables, description);
|
|
||||||
boost::program_options::notify(variables);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurationManager::loadConfig(const boost::filesystem::path& path,
|
|
||||||
boost::program_options::variables_map& variables,
|
|
||||||
boost::program_options::options_description& description)
|
|
||||||
{
|
|
||||||
boost::filesystem::path cfgFile(path);
|
|
||||||
cfgFile /= std::string(openmwCfgFile);
|
|
||||||
if (boost::filesystem::is_regular_file(cfgFile))
|
|
||||||
{
|
|
||||||
std::cout << "Loading config file: " << cfgFile.string() << "... ";
|
|
||||||
|
|
||||||
std::ifstream configFileStream(cfgFile.string().c_str());
|
|
||||||
if (configFileStream.is_open())
|
|
||||||
{
|
|
||||||
boost::program_options::store(boost::program_options::parse_config_file(
|
|
||||||
configFileStream, description), variables);
|
|
||||||
|
|
||||||
std::cout << "done." << std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << "failed." << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getGlobalConfigPath() const
|
|
||||||
{
|
|
||||||
return mPath.getGlobalConfigPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurationManager::setGlobalConfigPath(const boost::filesystem::path& newPath)
|
|
||||||
{
|
|
||||||
mPath.setGlobalConfigPath(newPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getLocalConfigPath() const
|
|
||||||
{
|
|
||||||
return mPath.getLocalConfigPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurationManager::setLocalConfigPath(const boost::filesystem::path& newPath)
|
|
||||||
{
|
|
||||||
mPath.setLocalConfigPath(newPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getRuntimeConfigPath() const
|
|
||||||
{
|
|
||||||
return mPath.getRuntimeConfigPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurationManager::setRuntimeConfigPath(const boost::filesystem::path& newPath)
|
|
||||||
{
|
|
||||||
mPath.setRuntimeConfigPath(newPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getGlobalDataPath() const
|
|
||||||
{
|
|
||||||
return mPath.getGlobalDataPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurationManager::setGlobalDataPath(const boost::filesystem::path& newPath)
|
|
||||||
{
|
|
||||||
mPath.setGlobalDataPath(newPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getLocalDataPath() const
|
|
||||||
{
|
|
||||||
return mPath.getLocalDataPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurationManager::setLocalDataPath(const boost::filesystem::path& newPath)
|
|
||||||
{
|
|
||||||
mPath.setLocalDataPath(newPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getRuntimeDataPath() const
|
|
||||||
{
|
|
||||||
return mPath.getRuntimeDataPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurationManager::setRuntimeDataPath(const boost::filesystem::path& newPath)
|
|
||||||
{
|
|
||||||
mPath.setRuntimeDataPath(newPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getOgreConfigPath() const
|
|
||||||
{
|
|
||||||
return mOgreCfgPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getPluginsConfigPath() const
|
|
||||||
{
|
|
||||||
return mPluginsCfgPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getLogPath() const
|
|
||||||
{
|
|
||||||
return mLogPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace Cfg */
|
|
@ -1,62 +0,0 @@
|
|||||||
#ifndef COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP
|
|
||||||
#define COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP
|
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
#include <components/files/path.hpp>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \namespace Cfg
|
|
||||||
*/
|
|
||||||
namespace Cfg
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \struct ConfigurationManager
|
|
||||||
*/
|
|
||||||
struct ConfigurationManager
|
|
||||||
{
|
|
||||||
ConfigurationManager();
|
|
||||||
virtual ~ConfigurationManager();
|
|
||||||
|
|
||||||
void readConfiguration(boost::program_options::variables_map& variables,
|
|
||||||
boost::program_options::options_description& description);
|
|
||||||
|
|
||||||
const boost::filesystem::path& getGlobalConfigPath() const;
|
|
||||||
void setGlobalConfigPath(const boost::filesystem::path& newPath);
|
|
||||||
|
|
||||||
const boost::filesystem::path& getLocalConfigPath() const;
|
|
||||||
void setLocalConfigPath(const boost::filesystem::path& newPath);
|
|
||||||
|
|
||||||
const boost::filesystem::path& getRuntimeConfigPath() const;
|
|
||||||
void setRuntimeConfigPath(const boost::filesystem::path& newPath);
|
|
||||||
|
|
||||||
const boost::filesystem::path& getGlobalDataPath() const;
|
|
||||||
void setGlobalDataPath(const boost::filesystem::path& newPath);
|
|
||||||
|
|
||||||
const boost::filesystem::path& getLocalDataPath() const;
|
|
||||||
void setLocalDataPath(const boost::filesystem::path& newPath);
|
|
||||||
|
|
||||||
const boost::filesystem::path& getRuntimeDataPath() const;
|
|
||||||
void setRuntimeDataPath(const boost::filesystem::path& newPath);
|
|
||||||
|
|
||||||
const boost::filesystem::path& getOgreConfigPath() const;
|
|
||||||
const boost::filesystem::path& getPluginsConfigPath() const;
|
|
||||||
const boost::filesystem::path& getLogPath() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void loadConfig(const boost::filesystem::path& path,
|
|
||||||
boost::program_options::variables_map& variables,
|
|
||||||
boost::program_options::options_description& description);
|
|
||||||
|
|
||||||
Files::Path<> mPath;
|
|
||||||
|
|
||||||
boost::filesystem::path mOgreCfgPath;
|
|
||||||
boost::filesystem::path mPluginsCfgPath;
|
|
||||||
boost::filesystem::path mLogPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* namespace Cfg */
|
|
||||||
|
|
||||||
#endif /* COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP */
|
|
@ -0,0 +1,182 @@
|
|||||||
|
#include "configurationmanager.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/algorithm/string/erase.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \namespace Files
|
||||||
|
*/
|
||||||
|
namespace Files
|
||||||
|
{
|
||||||
|
|
||||||
|
static const char* const openmwCfgFile = "openmw.cfg";
|
||||||
|
static const char* const ogreCfgFile = "ogre.cfg";
|
||||||
|
static const char* const pluginsCfgFile = "plugins.cfg";
|
||||||
|
|
||||||
|
const char* const mwToken = "?mw?";
|
||||||
|
const char* const localToken = "?local?";
|
||||||
|
const char* const userToken = "?user?";
|
||||||
|
const char* const globalToken = "?global?";
|
||||||
|
|
||||||
|
ConfigurationManager::ConfigurationManager()
|
||||||
|
: mFixedPath("openmw")
|
||||||
|
{
|
||||||
|
setupTokensMapping();
|
||||||
|
|
||||||
|
mPluginsCfgPath = mFixedPath.getGlobalPath() / pluginsCfgFile;
|
||||||
|
if (!boost::filesystem::is_regular_file(mPluginsCfgPath))
|
||||||
|
{
|
||||||
|
mPluginsCfgPath = mFixedPath.getLocalPath() / pluginsCfgFile;
|
||||||
|
if (!boost::filesystem::is_regular_file(mPluginsCfgPath))
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to find " << pluginsCfgFile << " file!" << std::endl;
|
||||||
|
mPluginsCfgPath.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mOgreCfgPath = mFixedPath.getUserPath() / ogreCfgFile;
|
||||||
|
mLogPath = mFixedPath.getUserPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigurationManager::~ConfigurationManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationManager::setupTokensMapping()
|
||||||
|
{
|
||||||
|
mTokensMapping.insert(std::make_pair(mwToken, &FixedPath<>::getInstallPath));
|
||||||
|
mTokensMapping.insert(std::make_pair(localToken, &FixedPath<>::getLocalPath));
|
||||||
|
mTokensMapping.insert(std::make_pair(userToken, &FixedPath<>::getUserPath));
|
||||||
|
mTokensMapping.insert(std::make_pair(globalToken, &FixedPath<>::getGlobalDataPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables,
|
||||||
|
boost::program_options::options_description& description)
|
||||||
|
{
|
||||||
|
loadConfig(mFixedPath.getUserPath(), variables, description);
|
||||||
|
boost::program_options::notify(variables);
|
||||||
|
|
||||||
|
loadConfig(mFixedPath.getLocalPath(), variables, description);
|
||||||
|
boost::program_options::notify(variables);
|
||||||
|
loadConfig(mFixedPath.getGlobalPath(), variables, description);
|
||||||
|
boost::program_options::notify(variables);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationManager::processPaths(Files::PathContainer& dataDirs)
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
|
||||||
|
{
|
||||||
|
path = it->string();
|
||||||
|
boost::erase_all(path, "\"");
|
||||||
|
*it = boost::filesystem::path(path);
|
||||||
|
|
||||||
|
// Check if path contains a token
|
||||||
|
if (!path.empty() && *path.begin() == '?')
|
||||||
|
{
|
||||||
|
std::string::size_type pos = path.find('?', 1);
|
||||||
|
if (pos != std::string::npos && pos != 0)
|
||||||
|
{
|
||||||
|
TokensMappingContainer::iterator tokenIt = mTokensMapping.find(path.substr(0, pos + 1));
|
||||||
|
if (tokenIt != mTokensMapping.end())
|
||||||
|
{
|
||||||
|
boost::filesystem::path tempPath(((mFixedPath).*(tokenIt->second))());
|
||||||
|
if (pos < path.length() - 1)
|
||||||
|
{
|
||||||
|
// There is something after the token, so we should
|
||||||
|
// append it to the path
|
||||||
|
tempPath /= path.substr(pos + 1, path.length() - pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
*it = tempPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Clean invalid / unknown token, it will be removed outside the loop
|
||||||
|
(*it).clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boost::filesystem::is_directory(*it))
|
||||||
|
{
|
||||||
|
(*it).clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataDirs.erase(std::remove_if(dataDirs.begin(), dataDirs.end(),
|
||||||
|
boost::bind(&boost::filesystem::path::empty, _1)), dataDirs.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationManager::loadConfig(const boost::filesystem::path& path,
|
||||||
|
boost::program_options::variables_map& variables,
|
||||||
|
boost::program_options::options_description& description)
|
||||||
|
{
|
||||||
|
boost::filesystem::path cfgFile(path);
|
||||||
|
cfgFile /= std::string(openmwCfgFile);
|
||||||
|
if (boost::filesystem::is_regular_file(cfgFile))
|
||||||
|
{
|
||||||
|
std::cout << "Loading config file: " << cfgFile.string() << "... ";
|
||||||
|
|
||||||
|
std::ifstream configFileStream(cfgFile.string().c_str());
|
||||||
|
if (configFileStream.is_open())
|
||||||
|
{
|
||||||
|
boost::program_options::store(boost::program_options::parse_config_file(
|
||||||
|
configFileStream, description, true), variables);
|
||||||
|
|
||||||
|
std::cout << "done." << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "failed." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
|
||||||
|
{
|
||||||
|
return mFixedPath.getGlobalPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getUserPath() const
|
||||||
|
{
|
||||||
|
return mFixedPath.getUserPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getLocalPath() const
|
||||||
|
{
|
||||||
|
return mFixedPath.getLocalPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getGlobalDataPath() const
|
||||||
|
{
|
||||||
|
return mFixedPath.getGlobalDataPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getInstallPath() const
|
||||||
|
{
|
||||||
|
return mFixedPath.getInstallPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getOgreConfigPath() const
|
||||||
|
{
|
||||||
|
return mOgreCfgPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getPluginsConfigPath() const
|
||||||
|
{
|
||||||
|
return mPluginsCfgPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getLogPath() const
|
||||||
|
{
|
||||||
|
return mLogPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace Cfg */
|
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP
|
||||||
|
#define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <boost/tr1/tr1/unordered_map>
|
||||||
|
#else
|
||||||
|
#include <tr1/unordered_map>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#include <components/files/fixedpath.hpp>
|
||||||
|
#include <components/files/collections.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \namespace Files
|
||||||
|
*/
|
||||||
|
namespace Files
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \struct ConfigurationManager
|
||||||
|
*/
|
||||||
|
struct ConfigurationManager
|
||||||
|
{
|
||||||
|
ConfigurationManager();
|
||||||
|
virtual ~ConfigurationManager();
|
||||||
|
|
||||||
|
void readConfiguration(boost::program_options::variables_map& variables,
|
||||||
|
boost::program_options::options_description& description);
|
||||||
|
void processPaths(Files::PathContainer& dataDirs);
|
||||||
|
|
||||||
|
/**< Fixed paths */
|
||||||
|
const boost::filesystem::path& getGlobalPath() const;
|
||||||
|
const boost::filesystem::path& getUserPath() const;
|
||||||
|
const boost::filesystem::path& getLocalPath() const;
|
||||||
|
|
||||||
|
const boost::filesystem::path& getGlobalDataPath() const;
|
||||||
|
const boost::filesystem::path& getUserDataPath() const;
|
||||||
|
const boost::filesystem::path& getLocalDataPath() const;
|
||||||
|
const boost::filesystem::path& getInstallPath() const;
|
||||||
|
|
||||||
|
const boost::filesystem::path& getOgreConfigPath() const;
|
||||||
|
const boost::filesystem::path& getPluginsConfigPath() const;
|
||||||
|
const boost::filesystem::path& getLogPath() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef Files::FixedPath<> FixedPathType;
|
||||||
|
|
||||||
|
typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const;
|
||||||
|
typedef std::tr1::unordered_map<std::string, path_type_f> TokensMappingContainer;
|
||||||
|
|
||||||
|
void loadConfig(const boost::filesystem::path& path,
|
||||||
|
boost::program_options::variables_map& variables,
|
||||||
|
boost::program_options::options_description& description);
|
||||||
|
|
||||||
|
void setupTokensMapping();
|
||||||
|
|
||||||
|
FixedPathType mFixedPath;
|
||||||
|
|
||||||
|
boost::filesystem::path mOgreCfgPath;
|
||||||
|
boost::filesystem::path mPluginsCfgPath;
|
||||||
|
boost::filesystem::path mLogPath;
|
||||||
|
|
||||||
|
TokensMappingContainer mTokensMapping;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace Cfg */
|
||||||
|
|
||||||
|
#endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */
|
@ -0,0 +1,120 @@
|
|||||||
|
#include "filelibrary.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
namespace Files
|
||||||
|
{
|
||||||
|
// Looks for a string in a vector of strings
|
||||||
|
bool containsVectorString(const StringVector& list, const std::string& str)
|
||||||
|
{
|
||||||
|
for (StringVector::const_iterator iter = list.begin();
|
||||||
|
iter != list.end(); iter++)
|
||||||
|
{
|
||||||
|
if (*iter == str)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches a path and adds the results to the library
|
||||||
|
void FileLibrary::add(const boost::filesystem::path &root, bool recursive, bool strict,
|
||||||
|
const StringVector &acceptableExtensions)
|
||||||
|
{
|
||||||
|
if (!boost::filesystem::exists(root))
|
||||||
|
{
|
||||||
|
std::cout << "Warning " << root.string() << " does not exist.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fileExtension;
|
||||||
|
std::string type;
|
||||||
|
|
||||||
|
// remember the last location of the priority list when listing new items
|
||||||
|
int length = mPriorityList.size();
|
||||||
|
|
||||||
|
// First makes a list of all candidate files
|
||||||
|
FileLister(root, mPriorityList, recursive);
|
||||||
|
|
||||||
|
// Then sort these files into sections according to the folder they belong to
|
||||||
|
for (PathContainer::iterator listIter = mPriorityList.begin() + length;
|
||||||
|
listIter != mPriorityList.end(); ++listIter)
|
||||||
|
{
|
||||||
|
if( !acceptableExtensions.empty() )
|
||||||
|
{
|
||||||
|
fileExtension = boost::filesystem::path (listIter->extension()).string();
|
||||||
|
boost::algorithm::to_lower(fileExtension);
|
||||||
|
if(!containsVectorString(acceptableExtensions, fileExtension))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = boost::filesystem::path (listIter->parent_path().leaf()).string();
|
||||||
|
if (!strict)
|
||||||
|
boost::algorithm::to_lower(type);
|
||||||
|
|
||||||
|
mMap[type].push_back(*listIter);
|
||||||
|
// std::cout << "Added path: " << listIter->string() << " in section "<< type <<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the named section exists
|
||||||
|
bool FileLibrary::containsSection(std::string sectionName, bool strict)
|
||||||
|
{
|
||||||
|
if (!strict)
|
||||||
|
boost::algorithm::to_lower(sectionName);
|
||||||
|
StringPathContMap::const_iterator mapIter = mMap.find(sectionName);
|
||||||
|
if (mapIter == mMap.end())
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a pointer to const for a section of the library
|
||||||
|
const PathContainer* FileLibrary::section(std::string sectionName, bool strict)
|
||||||
|
{
|
||||||
|
if (!strict)
|
||||||
|
boost::algorithm::to_lower(sectionName);
|
||||||
|
StringPathContMap::const_iterator mapIter = mMap.find(sectionName);
|
||||||
|
if (mapIter == mMap.end())
|
||||||
|
{
|
||||||
|
//std::cout << "Empty\n";
|
||||||
|
return &mEmptyPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return &(mapIter->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches the library for an item and returns a boost path to it
|
||||||
|
boost::filesystem::path FileLibrary::locate(std::string item, bool strict, std::string sectionName)
|
||||||
|
{
|
||||||
|
boost::filesystem::path result("");
|
||||||
|
if (sectionName == "")
|
||||||
|
{
|
||||||
|
return FileListLocator(mPriorityList, boost::filesystem::path(item), strict);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!containsSection(sectionName, strict))
|
||||||
|
{
|
||||||
|
std::cout << "Warning: There is no section named " << sectionName << "\n";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = FileListLocator(mMap[sectionName], boost::filesystem::path(item), strict);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints all the available sections, used for debugging
|
||||||
|
void FileLibrary::printSections()
|
||||||
|
{
|
||||||
|
for(StringPathContMap::const_iterator mapIter = mMap.begin();
|
||||||
|
mapIter != mMap.end(); mapIter++)
|
||||||
|
{
|
||||||
|
std::cout << mapIter->first <<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef COMPONENTS_FILES_FILELIBRARY_HPP
|
||||||
|
#define COMPONENTS_FILES_FILELIBRARY_HPP
|
||||||
|
|
||||||
|
#include <components/files/fileops.hpp>
|
||||||
|
|
||||||
|
namespace Files
|
||||||
|
{
|
||||||
|
typedef std::map<std::string, PathContainer> StringPathContMap;
|
||||||
|
typedef std::vector<std::string> StringVector;
|
||||||
|
|
||||||
|
/// Looks for a string in a vector of strings
|
||||||
|
bool containsVectorString(const StringVector& list, const std::string& str);
|
||||||
|
|
||||||
|
/// \brief Searches directories and makes lists of files according to folder name
|
||||||
|
class FileLibrary
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
StringPathContMap mMap;
|
||||||
|
PathContainer mEmptyPath;
|
||||||
|
PathContainer mPriorityList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Searches a path and adds the results to the library
|
||||||
|
/// Recursive search and fs strict options are available
|
||||||
|
/// Takes a vector of acceptable files extensions, if none is given it lists everything.
|
||||||
|
void add(const boost::filesystem::path &root, bool recursive, bool strict,
|
||||||
|
const StringVector &acceptableExtensions);
|
||||||
|
|
||||||
|
/// Returns true if the named section exists
|
||||||
|
/// You can run this check before running section()
|
||||||
|
bool containsSection(std::string sectionName, bool strict);
|
||||||
|
|
||||||
|
/// Returns a pointer to const for a section of the library
|
||||||
|
/// which is essentially a PathContainer.
|
||||||
|
/// If the section does not exists it returns a pointer to an empty path.
|
||||||
|
const PathContainer* section(std::string sectionName, bool strict);
|
||||||
|
|
||||||
|
/// Searches the library for an item and returns a boost path to it
|
||||||
|
/// Optionally you can provide a specific section
|
||||||
|
/// The result is the first that comes up according to alphabetical
|
||||||
|
/// section naming
|
||||||
|
boost::filesystem::path locate(std::string item, bool strict, std::string sectionName="");
|
||||||
|
|
||||||
|
/// Prints all the available sections, used for debugging
|
||||||
|
void printSections();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* Open Morrowind - an opensource Elder Scrolls III: Morrowind
|
||||||
|
* engine implementation.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Open Morrowind Team
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file components/files/fixedpath.hpp */
|
||||||
|
|
||||||
|
#ifndef COMPONENTS_FILES_FIXEDPATH_HPP
|
||||||
|
#define COMPONENTS_FILES_FIXEDPATH_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__FreeBSD__)
|
||||||
|
#include <components/files/linuxpath.hpp>
|
||||||
|
namespace Files { typedef LinuxPath TargetPathType; }
|
||||||
|
|
||||||
|
#elif defined(__WIN32) || defined(__WINDOWS__) || defined(_WIN32)
|
||||||
|
#include <components/files/windowspath.hpp>
|
||||||
|
namespace Files { typedef WindowsPath TargetPathType; }
|
||||||
|
|
||||||
|
#elif defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__)
|
||||||
|
#include <components/files/macospath.hpp>
|
||||||
|
namespace Files { typedef MacOsPath TargetPathType; }
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \namespace Files
|
||||||
|
*/
|
||||||
|
namespace Files
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \struct Path
|
||||||
|
*
|
||||||
|
* \tparam P - Path strategy class type (depends on target system)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template
|
||||||
|
<
|
||||||
|
class P = TargetPathType
|
||||||
|
>
|
||||||
|
struct FixedPath
|
||||||
|
{
|
||||||
|
typedef P PathType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Path constructor.
|
||||||
|
*
|
||||||
|
* \param [in] application_name - Name of the application
|
||||||
|
*/
|
||||||
|
FixedPath(const std::string& application_name)
|
||||||
|
: mPath()
|
||||||
|
, mUserPath(mPath.getUserPath())
|
||||||
|
, mGlobalPath(mPath.getGlobalPath())
|
||||||
|
, mLocalPath(mPath.getLocalPath())
|
||||||
|
, mGlobalDataPath(mPath.getGlobalDataPath())
|
||||||
|
, mInstallPath(mPath.getInstallPath())
|
||||||
|
{
|
||||||
|
if (!application_name.empty())
|
||||||
|
{
|
||||||
|
boost::filesystem::path suffix(application_name + std::string("/"));
|
||||||
|
|
||||||
|
mUserPath /= suffix;
|
||||||
|
mGlobalPath /= suffix;
|
||||||
|
mGlobalDataPath /= suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return path pointing to the user local configuration directory.
|
||||||
|
*
|
||||||
|
* \return boost::filesystem::path
|
||||||
|
*/
|
||||||
|
const boost::filesystem::path& getUserPath() const
|
||||||
|
{
|
||||||
|
return mUserPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return path pointing to the global (system) configuration directory.
|
||||||
|
*
|
||||||
|
* \return boost::filesystem::path
|
||||||
|
*/
|
||||||
|
const boost::filesystem::path& getGlobalPath() const
|
||||||
|
{
|
||||||
|
return mGlobalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return path pointing to the directory where application was started.
|
||||||
|
*
|
||||||
|
* \return boost::filesystem::path
|
||||||
|
*/
|
||||||
|
const boost::filesystem::path& getLocalPath() const
|
||||||
|
{
|
||||||
|
return mLocalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& getInstallPath() const
|
||||||
|
{
|
||||||
|
return mInstallPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& getGlobalDataPath() const
|
||||||
|
{
|
||||||
|
return mGlobalDataPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PathType mPath;
|
||||||
|
|
||||||
|
boost::filesystem::path mUserPath; /**< User path */
|
||||||
|
boost::filesystem::path mGlobalPath; /**< Global path */
|
||||||
|
boost::filesystem::path mLocalPath; /**< It is the same directory where application was run */
|
||||||
|
|
||||||
|
boost::filesystem::path mGlobalDataPath; /**< Global application data path */
|
||||||
|
|
||||||
|
boost::filesystem::path mInstallPath;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace Files */
|
||||||
|
|
||||||
|
#endif /* COMPONENTS_FILES_FIXEDPATH_HPP */
|
@ -1,232 +0,0 @@
|
|||||||
/**
|
|
||||||
* Open Morrowind - an opensource Elder Scrolls III: Morrowind
|
|
||||||
* engine implementation.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2011 Open Morrowind Team
|
|
||||||
*
|
|
||||||
* This program 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.
|
|
||||||
*
|
|
||||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file components/files/path.hpp */
|
|
||||||
|
|
||||||
#ifndef COMPONENTS_FILES_PATH_HPP
|
|
||||||
#define COMPONENTS_FILES_PATH_HPP
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
#include <components/files/linuxpath.hpp>
|
|
||||||
namespace Files { typedef LinuxPath TargetPathType; }
|
|
||||||
|
|
||||||
#elif defined(__WIN32) || defined(__WINDOWS__) || defined (_WINDOWS)
|
|
||||||
#include <components/files/windowspath.hpp>
|
|
||||||
namespace Files { typedef WindowsPath TargetPathType; }
|
|
||||||
|
|
||||||
#elif defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__)
|
|
||||||
#include <components/files/macospath.hpp>
|
|
||||||
namespace Files { typedef MacOsPath TargetPathType; }
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "Unknown platform!"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \namespace Files
|
|
||||||
*/
|
|
||||||
namespace Files
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \struct Path
|
|
||||||
*
|
|
||||||
* \tparam P - Path strategy class type (depends on target system)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
template
|
|
||||||
<
|
|
||||||
class P = TargetPathType
|
|
||||||
>
|
|
||||||
struct Path
|
|
||||||
{
|
|
||||||
typedef P PathType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Path constructor.
|
|
||||||
*
|
|
||||||
* \param [in] application_name - Name of the application
|
|
||||||
*/
|
|
||||||
Path(const std::string& application_name)
|
|
||||||
: mPath()
|
|
||||||
, mLocalConfigPath(mPath.getLocalConfigPath())
|
|
||||||
, mGlobalConfigPath(mPath.getGlobalConfigPath())
|
|
||||||
, mRuntimeConfigPath(mPath.getRuntimeConfigPath())
|
|
||||||
, mLocalDataPath(mPath.getLocalDataPath())
|
|
||||||
, mGlobalDataPath(mPath.getGlobalDataPath())
|
|
||||||
, mRuntimeDataPath(mPath.getRuntimeDataPath())
|
|
||||||
{
|
|
||||||
if (!application_name.empty())
|
|
||||||
{
|
|
||||||
boost::filesystem::path suffix(application_name + std::string("/"));
|
|
||||||
|
|
||||||
mLocalConfigPath /= suffix;
|
|
||||||
mGlobalConfigPath /= suffix;
|
|
||||||
|
|
||||||
mLocalDataPath /= suffix;
|
|
||||||
mGlobalDataPath /= suffix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Return path pointing to the user local configuration directory.
|
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
|
||||||
const boost::filesystem::path& getLocalConfigPath() const
|
|
||||||
{
|
|
||||||
return mLocalConfigPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Sets new local configuration path.
|
|
||||||
*
|
|
||||||
* \param [in] path - New path
|
|
||||||
*/
|
|
||||||
void setLocalConfigPath(const boost::filesystem::path& path)
|
|
||||||
{
|
|
||||||
mLocalConfigPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Return path pointing to the global (system) configuration directory.
|
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
|
||||||
const boost::filesystem::path& getGlobalConfigPath() const
|
|
||||||
{
|
|
||||||
return mGlobalConfigPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Sets new global configuration path.
|
|
||||||
*
|
|
||||||
* \param [in] path - New path
|
|
||||||
*/
|
|
||||||
void setGlobalConfigPath(const boost::filesystem::path& path)
|
|
||||||
{
|
|
||||||
mGlobalConfigPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Return path pointing to the directory where application was started.
|
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
|
||||||
const boost::filesystem::path& getRuntimeConfigPath() const
|
|
||||||
{
|
|
||||||
return mRuntimeConfigPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Sets new runtime configuration path.
|
|
||||||
*
|
|
||||||
* \param [in] path - New path
|
|
||||||
*/
|
|
||||||
void setRuntimeConfigPath(const boost::filesystem::path& path)
|
|
||||||
{
|
|
||||||
mRuntimeConfigPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Return path pointing to the user local data directory.
|
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
|
||||||
const boost::filesystem::path& getLocalDataPath() const
|
|
||||||
{
|
|
||||||
return mLocalDataPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Sets new local data path.
|
|
||||||
*
|
|
||||||
* \param [in] path - New path
|
|
||||||
*/
|
|
||||||
void setLocalDataPath(const boost::filesystem::path& path)
|
|
||||||
{
|
|
||||||
mLocalDataPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Return path pointing to the global (system) data directory.
|
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
|
||||||
const boost::filesystem::path& getGlobalDataPath() const
|
|
||||||
{
|
|
||||||
return mGlobalDataPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Sets new global (system) data directory.
|
|
||||||
*
|
|
||||||
* \param [in] path - New path
|
|
||||||
*/
|
|
||||||
void setGlobalDataPath(const boost::filesystem::path& path)
|
|
||||||
{
|
|
||||||
mGlobalDataPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Return path pointing to the directory where application was started.
|
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
|
||||||
const boost::filesystem::path& getRuntimeDataPath() const
|
|
||||||
{
|
|
||||||
return mRuntimeDataPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Sets new runtime data directory.
|
|
||||||
*
|
|
||||||
* \param [in] path - New path
|
|
||||||
*/
|
|
||||||
void setRuntimeDataPath(const boost::filesystem::path& path)
|
|
||||||
{
|
|
||||||
mRuntimeDataPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PathType mPath;
|
|
||||||
|
|
||||||
boost::filesystem::path mLocalConfigPath; /**< User local path to the configuration files */
|
|
||||||
boost::filesystem::path mGlobalConfigPath; /**< Global path to the configuration files */
|
|
||||||
boost::filesystem::path mRuntimeConfigPath; /**< Runtime path to the configuration files.
|
|
||||||
By default it is the same directory where
|
|
||||||
application was run */
|
|
||||||
|
|
||||||
boost::filesystem::path mLocalDataPath; /**< User local application data path (user plugins / mods / etc.) */
|
|
||||||
boost::filesystem::path mGlobalDataPath; /**< Global application data path */
|
|
||||||
boost::filesystem::path mRuntimeDataPath; /**< Runtime path to the configuration files.
|
|
||||||
By default it is a 'data' directory in same
|
|
||||||
directory where application was run */
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} /* namespace Files */
|
|
||||||
|
|
||||||
#endif /* COMPONENTS_FILES_PATH_HPP */
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 14b2851e72f610ae81dd296598867e6fb0babd2a
|
|
@ -0,0 +1,3 @@
|
|||||||
|
upload_docs.sh
|
||||||
|
docs
|
||||||
|
*~
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,26 @@
|
|||||||
|
Minimal Abstraction Game Layer (Mangle) is licensed under the
|
||||||
|
'zlib/libpng' license:
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Copyright (c) 2009 Nicolay Korslund
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
|
@ -0,0 +1,129 @@
|
|||||||
|
Welcome to Mangle v0.1
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Written by: Nicolay Korslund (korslund@gmail.com)
|
||||||
|
License: zlib/png (see LICENSE.txt)
|
||||||
|
WWW: http://asm-soft.com/mangle/
|
||||||
|
Documentation: http://asm-soft.com/mangle/docs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Mangle is the project name for a small set of generic interfaces for
|
||||||
|
various game middleware libraries, such as sound, input, graphics, and
|
||||||
|
so on. You can imagine that it stands for "Minimal Abstraction Game
|
||||||
|
Layer", if you like. It will consist of several more or less
|
||||||
|
independent modules, one for each of these areas. These may be used
|
||||||
|
together to build an entire game engine, or they can be used
|
||||||
|
individually as separate libraries.
|
||||||
|
|
||||||
|
However, Mangle does NOT actually implement a game engine, or any new
|
||||||
|
fundamental functionality. More on that below.
|
||||||
|
|
||||||
|
Currently there's modules for sound and streams / archives (virtual
|
||||||
|
file systems.) More will come in the future (including input, 2D/3D
|
||||||
|
graphics, GUI, physics, and more.)
|
||||||
|
|
||||||
|
|
||||||
|
Main idea
|
||||||
|
---------
|
||||||
|
|
||||||
|
The idea behind Mangle is to provide a uniform, consistent interface
|
||||||
|
to other game libraries. The library does not provide ANY
|
||||||
|
functionality on its own. Instead it connects to a backend
|
||||||
|
implementation of your choice (or of your making.)
|
||||||
|
|
||||||
|
The Sound module, for example, currently has backends for OpenAL
|
||||||
|
(output only), FFmpeg (input only) and for Audiere. Hopefully we'll
|
||||||
|
add IrrKlang, FMod, DirectSound, Miles and more in the future. It can
|
||||||
|
combine libraries to get more complete functionality (like using
|
||||||
|
OpenAL for output and FFmpeg to decode sound files), and it's also
|
||||||
|
easy to write your own backend if you're using a different (or
|
||||||
|
home-brewed) sound system.
|
||||||
|
|
||||||
|
Regardless of what backend you use, the front-end interfaces (found
|
||||||
|
eg. in sound/output.h) is identical, and as a library user you
|
||||||
|
shouldn't notice much difference at all if you swap one backend for
|
||||||
|
another at a later point. It should Just Work.
|
||||||
|
|
||||||
|
The interfaces themselves are also quite simple. Setting up a sound
|
||||||
|
stream from FFmpeg or other decoder into OpenAL can be quite hairy -
|
||||||
|
but with Mangle the hairy parts have already been written for you. You
|
||||||
|
just plug the parts together.
|
||||||
|
|
||||||
|
The goal in the long run is to support a wide variety of game-related
|
||||||
|
libraries, and as many backend libraries (free and commercial) as
|
||||||
|
possible, so that you the user will have to write as little code as
|
||||||
|
possible.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
What is it good for
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The main point of Mangle, as we said above, is that it connects to any
|
||||||
|
library of your choice "behind the scenes" but provides the same,
|
||||||
|
super-simple interface front-end for all of them. There can benefit
|
||||||
|
you in many ways:
|
||||||
|
|
||||||
|
- If you want to use a new library that Mangle support. You don't have
|
||||||
|
to scour the net for tutorials and usage examples, since much of the
|
||||||
|
common usage code is already included in the implementation classes.
|
||||||
|
|
||||||
|
- If you don't want to pollute your code with library-specific code.
|
||||||
|
The Mangle interfaces can help you keep your code clean, and its
|
||||||
|
user interface is often simpler than the exteral library one.
|
||||||
|
|
||||||
|
- If you want to quickly connect different libraries together, it
|
||||||
|
really helps if they speak a common language. The Mangle interfaces
|
||||||
|
are exactly that - a common language between libraries. Do you need
|
||||||
|
Audiere to load sounds from a weird archive format only implemented
|
||||||
|
for PhysFS, all channeled through the OGRE resource system? No
|
||||||
|
problem!
|
||||||
|
|
||||||
|
- If you are creating a library that depends on a specific feature
|
||||||
|
(such as sound), but you don't want to lock your users into any
|
||||||
|
specific sound library. Mangle works as an abstraction that lets
|
||||||
|
your users select their own implementation.
|
||||||
|
|
||||||
|
- If you want to support multiple backends for your game/app, or want
|
||||||
|
to make it possible to easily switch backends later. You can select
|
||||||
|
backends at compile time or even at runtime. For example you might
|
||||||
|
want to switch to to a commercial sound library at a later stage in
|
||||||
|
development, or you may want to use a different input library on
|
||||||
|
console platforms than on PC.
|
||||||
|
|
||||||
|
The Mangle implementations are extremely light-weight - often just one
|
||||||
|
or two cpp/h pairs per module. You can plug them directly into your
|
||||||
|
program, there's no separate library building step required.
|
||||||
|
|
||||||
|
Since the library aims to be very modularly put together, you can
|
||||||
|
also, in many cases, just copy-and-paste the parts you need and ignore
|
||||||
|
the rest. Or modify stuff without fearing that the whole 'system' will
|
||||||
|
come crashing down, because there is no big 'system' to speak of.
|
||||||
|
|
||||||
|
|
||||||
|
Past and future
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Mangle started out as (and still is) a spin-off from OpenMW, another
|
||||||
|
project I am personally working on ( http://openmw.com/ ). OpenMW is
|
||||||
|
an attempt to recreate the engine behind the commercial game
|
||||||
|
Morrowind, using only open source software.
|
||||||
|
|
||||||
|
The projects are still tightly interlinked, and they will continue to
|
||||||
|
be until OpenMW is finished. Most near-future work on Mangle will be
|
||||||
|
focused chiefly on OpenMW at the moment. However I will gladly include
|
||||||
|
external contributions and suggestions that are not OpenMW-related if
|
||||||
|
someone sends them to me.
|
||||||
|
|
||||||
|
|
||||||
|
Conclusion
|
||||||
|
----------
|
||||||
|
|
||||||
|
As you might have guessed, Mangle is more a concept in development
|
||||||
|
than a finished library right now.
|
||||||
|
|
||||||
|
All feedback, ideas, concepts, questions and code are very
|
||||||
|
welcome. Send them to: korslund@gmail.com
|
||||||
|
|
||||||
|
I will put up a forum later as well if there's enough interest.
|
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef MANGLE_INPUT_OGREINPUTFRAME_H
|
||||||
|
#define MANGLE_INPUT_OGREINPUTFRAME_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
This Ogre FrameListener calls capture() on an input driver every frame.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <OgreFrameListener.h>
|
||||||
|
#include "../driver.hpp"
|
||||||
|
|
||||||
|
namespace Mangle {
|
||||||
|
namespace Input {
|
||||||
|
|
||||||
|
struct OgreInputCapture : Ogre::FrameListener
|
||||||
|
{
|
||||||
|
Mangle::Input::Driver &driver;
|
||||||
|
|
||||||
|
OgreInputCapture(Mangle::Input::Driver &drv)
|
||||||
|
: driver(drv) {}
|
||||||
|
|
||||||
|
bool frameStarted(const Ogre::FrameEvent &evt)
|
||||||
|
{
|
||||||
|
driver.capture();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,69 @@
|
|||||||
|
#ifndef MANGLE_INPUT_DRIVER_H
|
||||||
|
#define MANGLE_INPUT_DRIVER_H
|
||||||
|
|
||||||
|
#include "event.hpp"
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
/** Input::Driver is the main interface to any input system that
|
||||||
|
handles keyboard and/or mouse input, along with any other
|
||||||
|
input source like joysticks.
|
||||||
|
|
||||||
|
It is really a generalized event system, and could also be
|
||||||
|
used for non-input related events. The definition of the event
|
||||||
|
codes and structures are entirely dependent on the
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
A system-independent key code list will be found in keys.hpp,
|
||||||
|
and input drivers should privide optional translations to/from
|
||||||
|
this list for full compatibility.
|
||||||
|
*/
|
||||||
|
struct Driver
|
||||||
|
{
|
||||||
|
Driver() {}
|
||||||
|
virtual ~Driver() {}
|
||||||
|
|
||||||
|
/** Captures input and produces the relevant events from it. An
|
||||||
|
event callback must be set with setEvent(), or all events
|
||||||
|
will be ignored.
|
||||||
|
*/
|
||||||
|
virtual void capture() = 0;
|
||||||
|
|
||||||
|
/** Check the state of a given key or button. The key/button
|
||||||
|
definitions depends on the driver.
|
||||||
|
*/
|
||||||
|
virtual bool isDown(int index) = 0;
|
||||||
|
|
||||||
|
/** Show or hide system mouse cursor
|
||||||
|
*/
|
||||||
|
virtual void showMouse(bool show) = 0;
|
||||||
|
|
||||||
|
/** Set the event handler for input events. The evt->event()
|
||||||
|
function is called for each event. The meaning of the index
|
||||||
|
and *p parameters will be specific to each driver and to
|
||||||
|
each input system.
|
||||||
|
*/
|
||||||
|
void setEvent(EventPtr evt)
|
||||||
|
{ event = evt; }
|
||||||
|
|
||||||
|
/** Instigate an event. Is used internally for all events, but
|
||||||
|
can also be called from the outside to "fake" events from
|
||||||
|
this driver.
|
||||||
|
*/
|
||||||
|
void makeEvent(Event::Type type, int index, const void *p=NULL)
|
||||||
|
{
|
||||||
|
if(event)
|
||||||
|
event->event(type,index,p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Holds the event callback set byt setEvent()
|
||||||
|
EventPtr event;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<Driver> DriverPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef MANGLE_INPUT_EVENT_H
|
||||||
|
#define MANGLE_INPUT_EVENT_H
|
||||||
|
|
||||||
|
#include "../tools/shared_ptr.hpp"
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
/** Generic callback for input events. The meaning of the
|
||||||
|
parameters depend on the system producing the events.
|
||||||
|
*/
|
||||||
|
struct Event
|
||||||
|
{
|
||||||
|
/// Event types
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
EV_Unknown = 1, // Unknown event type
|
||||||
|
EV_KeyDown = 2, // Keyboard button was pressed
|
||||||
|
EV_KeyUp = 4, // Keyboard button was released
|
||||||
|
EV_Keyboard = 6, // All keyboard events
|
||||||
|
|
||||||
|
EV_MouseMove = 8, // Mouse movement
|
||||||
|
EV_MouseDown = 16, // Mouse button pressed
|
||||||
|
EV_MouseUp = 32, // Mouse button released
|
||||||
|
EV_Mouse = 56, // All mouse events
|
||||||
|
|
||||||
|
EV_ALL = 63 // All events
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Called upon all events. The first parameter give the event
|
||||||
|
type, the second gives additional data (usually the local
|
||||||
|
keysym or button index as defined by the driver), and the
|
||||||
|
pointer points to the full custom event structure provided by
|
||||||
|
the driver (the type may vary depending on the EventType,
|
||||||
|
this is defined in the Driver documentation.)
|
||||||
|
*/
|
||||||
|
virtual void event(Type type, int index, const void *p) = 0;
|
||||||
|
virtual ~Event() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<Event> EventPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef MANGLE_INPUT_EVENTLIST_H
|
||||||
|
#define MANGLE_INPUT_EVENTLIST_H
|
||||||
|
|
||||||
|
#include "../event.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
/** And Event handler that distributes each event to a list of
|
||||||
|
other handlers. Supports filtering events by their Type
|
||||||
|
parameter.
|
||||||
|
*/
|
||||||
|
struct EventList : Event
|
||||||
|
{
|
||||||
|
struct Filter
|
||||||
|
{
|
||||||
|
EventPtr evt;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
std::vector<Filter> list;
|
||||||
|
|
||||||
|
void add(EventPtr e, int flags = EV_ALL)
|
||||||
|
{
|
||||||
|
Filter f;
|
||||||
|
f.evt = e;
|
||||||
|
f.flags = flags;
|
||||||
|
list.push_back(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void event(Type type, int index, const void *p)
|
||||||
|
{
|
||||||
|
std::vector<Filter>::iterator it;
|
||||||
|
|
||||||
|
for(it=list.begin(); it!=list.end(); it++)
|
||||||
|
{
|
||||||
|
if(type & it->flags)
|
||||||
|
it->evt->event(type,index,p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<EventList> EventListPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,148 @@
|
|||||||
|
#include "ois_driver.hpp"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <OgreRenderWindow.h>
|
||||||
|
#include <OIS/OIS.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE_CC__
|
||||||
|
#include <Carbon/Carbon.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace Mangle::Input;
|
||||||
|
using namespace OIS;
|
||||||
|
|
||||||
|
struct Mangle::Input::OISListener : OIS::KeyListener, OIS::MouseListener
|
||||||
|
{
|
||||||
|
OISDriver &drv;
|
||||||
|
|
||||||
|
OISListener(OISDriver &driver)
|
||||||
|
: drv(driver) {}
|
||||||
|
|
||||||
|
bool keyPressed( const OIS::KeyEvent &arg )
|
||||||
|
{
|
||||||
|
drv.makeEvent(Event::EV_KeyDown, arg.key, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keyReleased( const OIS::KeyEvent &arg )
|
||||||
|
{
|
||||||
|
drv.makeEvent(Event::EV_KeyUp, arg.key, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
|
||||||
|
{
|
||||||
|
// Mouse button events are handled as key events
|
||||||
|
// TODO: Translate mouse buttons into pseudo-keysyms
|
||||||
|
drv.makeEvent(Event::EV_MouseDown, id, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
|
||||||
|
{
|
||||||
|
// TODO: ditto
|
||||||
|
drv.makeEvent(Event::EV_MouseUp, id, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mouseMoved( const OIS::MouseEvent &arg )
|
||||||
|
{
|
||||||
|
drv.makeEvent(Event::EV_MouseMove, -1, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
OISDriver::OISDriver(Ogre::RenderWindow *window, bool exclusive)
|
||||||
|
{
|
||||||
|
assert(window);
|
||||||
|
|
||||||
|
size_t windowHnd;
|
||||||
|
|
||||||
|
window->getCustomAttribute("WINDOW", &windowHnd);
|
||||||
|
|
||||||
|
std::ostringstream windowHndStr;
|
||||||
|
ParamList pl;
|
||||||
|
|
||||||
|
windowHndStr << windowHnd;
|
||||||
|
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
|
||||||
|
|
||||||
|
// Set non-exclusive mouse and keyboard input if the user requested
|
||||||
|
// it.
|
||||||
|
if(!exclusive)
|
||||||
|
{
|
||||||
|
#if defined OIS_WIN32_PLATFORM
|
||||||
|
pl.insert(std::make_pair(std::string("w32_mouse"),
|
||||||
|
std::string("DISCL_FOREGROUND" )));
|
||||||
|
pl.insert(std::make_pair(std::string("w32_mouse"),
|
||||||
|
std::string("DISCL_NONEXCLUSIVE")));
|
||||||
|
pl.insert(std::make_pair(std::string("w32_keyboard"),
|
||||||
|
std::string("DISCL_FOREGROUND")));
|
||||||
|
pl.insert(std::make_pair(std::string("w32_keyboard"),
|
||||||
|
std::string("DISCL_NONEXCLUSIVE")));
|
||||||
|
#elif defined OIS_LINUX_PLATFORM
|
||||||
|
pl.insert(std::make_pair(std::string("x11_mouse_grab"),
|
||||||
|
std::string("false")));
|
||||||
|
pl.insert(std::make_pair(std::string("x11_mouse_hide"),
|
||||||
|
std::string("false")));
|
||||||
|
pl.insert(std::make_pair(std::string("x11_keyboard_grab"),
|
||||||
|
std::string("false")));
|
||||||
|
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
|
||||||
|
std::string("true")));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE_CC__
|
||||||
|
// Give the application window focus to receive input events
|
||||||
|
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
||||||
|
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||||
|
SetFrontProcess(&psn);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inputMgr = InputManager::createInputSystem( pl );
|
||||||
|
|
||||||
|
// Create all devices
|
||||||
|
keyboard = static_cast<Keyboard*>(inputMgr->createInputObject
|
||||||
|
( OISKeyboard, true ));
|
||||||
|
mouse = static_cast<Mouse*>(inputMgr->createInputObject
|
||||||
|
( OISMouse, true ));
|
||||||
|
|
||||||
|
// Set mouse region
|
||||||
|
const MouseState &ms = mouse->getMouseState();
|
||||||
|
ms.width = window->getWidth();
|
||||||
|
ms.height = window->getHeight();
|
||||||
|
|
||||||
|
// Set up the input listener
|
||||||
|
listener = new OISListener(*this);
|
||||||
|
keyboard-> setEventCallback(listener);
|
||||||
|
mouse-> setEventCallback(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
OISDriver::~OISDriver()
|
||||||
|
{
|
||||||
|
// Delete the listener object
|
||||||
|
if(listener)
|
||||||
|
delete listener;
|
||||||
|
|
||||||
|
if(inputMgr == NULL) return;
|
||||||
|
|
||||||
|
// Kill the input systems. This will reset input options such as key
|
||||||
|
// repeat rate.
|
||||||
|
inputMgr->destroyInputObject(keyboard);
|
||||||
|
inputMgr->destroyInputObject(mouse);
|
||||||
|
InputManager::destroyInputSystem(inputMgr);
|
||||||
|
inputMgr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OISDriver::capture()
|
||||||
|
{
|
||||||
|
// Capture keyboard and mouse events
|
||||||
|
keyboard->capture();
|
||||||
|
mouse->capture();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OISDriver::isDown(int index)
|
||||||
|
{
|
||||||
|
// TODO: Extend to mouse buttons as well
|
||||||
|
return keyboard->isKeyDown((OIS::KeyCode)index);
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef MANGLE_INPUT_OIS_DRIVER_H
|
||||||
|
#define MANGLE_INPUT_OIS_DRIVER_H
|
||||||
|
|
||||||
|
#include "../driver.hpp"
|
||||||
|
|
||||||
|
namespace OIS
|
||||||
|
{
|
||||||
|
class InputManager;
|
||||||
|
class Mouse;
|
||||||
|
class Keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Ogre
|
||||||
|
{
|
||||||
|
class RenderWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
struct OISListener;
|
||||||
|
|
||||||
|
/** Input driver for OIS, the input manager typically used with
|
||||||
|
Ogre.
|
||||||
|
*/
|
||||||
|
struct OISDriver : Driver
|
||||||
|
{
|
||||||
|
/// If exclusive=true, then we capture mouse and keyboard from
|
||||||
|
/// the OS.
|
||||||
|
OISDriver(Ogre::RenderWindow *window, bool exclusive=true);
|
||||||
|
~OISDriver();
|
||||||
|
|
||||||
|
void capture();
|
||||||
|
bool isDown(int index);
|
||||||
|
/// Not currently supported.
|
||||||
|
void showMouse(bool) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
OIS::InputManager *inputMgr;
|
||||||
|
OIS::Mouse *mouse;
|
||||||
|
OIS::Keyboard *keyboard;
|
||||||
|
|
||||||
|
OISListener *listener;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,54 @@
|
|||||||
|
#include "sdl_driver.hpp"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
using namespace Mangle::Input;
|
||||||
|
|
||||||
|
void SDLDriver::capture()
|
||||||
|
{
|
||||||
|
// Poll for events
|
||||||
|
SDL_Event evt;
|
||||||
|
while(SDL_PollEvent(&evt))
|
||||||
|
{
|
||||||
|
Event::Type type = Event::EV_Unknown;
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
|
switch(evt.type)
|
||||||
|
{
|
||||||
|
// For key events, send the keysym as the index.
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
type = Event::EV_KeyDown;
|
||||||
|
index = evt.key.keysym.sym;
|
||||||
|
break;
|
||||||
|
case SDL_KEYUP:
|
||||||
|
type = Event::EV_KeyUp;
|
||||||
|
index = evt.key.keysym.sym;
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
type = Event::EV_MouseMove;
|
||||||
|
break;
|
||||||
|
// Add more event types later
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass the event along, using -1 as index for unidentified
|
||||||
|
// event types.
|
||||||
|
makeEvent(type, index, &evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLDriver::isDown(int index)
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
Uint8 *keys = SDL_GetKeyState(&num);
|
||||||
|
assert(index >= 0 && index < num);
|
||||||
|
|
||||||
|
// The returned array from GetKeyState is indexed by the
|
||||||
|
// SDLK_KEYNAME enums and is just a list of bools. If the indexed
|
||||||
|
// value is true, the button is down.
|
||||||
|
return keys[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLDriver::showMouse(bool show)
|
||||||
|
{
|
||||||
|
SDL_ShowCursor(show?SDL_ENABLE:SDL_DISABLE);
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef MANGLE_INPUT_SDL_DRIVER_H
|
||||||
|
#define MANGLE_INPUT_SDL_DRIVER_H
|
||||||
|
|
||||||
|
#include "../driver.hpp"
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
/** Input driver for SDL. As the input system of SDL is seldomly
|
||||||
|
used alone (most often along with the video system), it is
|
||||||
|
assumed that you do your own initialization and cleanup of SDL
|
||||||
|
before and after using this driver.
|
||||||
|
|
||||||
|
The Event.event() calls will be given the proper EV_ type, the
|
||||||
|
key index (for key up/down events), and a pointer to the full
|
||||||
|
SDL_Event structure.
|
||||||
|
*/
|
||||||
|
struct SDLDriver : Driver
|
||||||
|
{
|
||||||
|
void capture();
|
||||||
|
bool isDown(int index);
|
||||||
|
void showMouse(bool);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,2 @@
|
|||||||
|
*_test
|
||||||
|
ogre.cfg
|
@ -0,0 +1,15 @@
|
|||||||
|
GCC=g++ -Wall
|
||||||
|
|
||||||
|
all: sdl_driver_test ois_driver_test evtlist_test
|
||||||
|
|
||||||
|
sdl_driver_test: sdl_driver_test.cpp
|
||||||
|
$(GCC) $< ../servers/sdl_driver.cpp -o $@ -I/usr/include/SDL/ -lSDL
|
||||||
|
|
||||||
|
ois_driver_test: ois_driver_test.cpp
|
||||||
|
$(GCC) $< ../servers/ois_driver.cpp -o $@ -I/usr/local/include/OGRE/ -lOgreMain -lOIS -lboost_filesystem
|
||||||
|
|
||||||
|
evtlist_test: evtlist_test.cpp ../filters/eventlist.hpp ../event.hpp
|
||||||
|
$(GCC) $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *_test
|
@ -0,0 +1,35 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "../driver.hpp"
|
||||||
|
#include <unistd.h>
|
||||||
|
using namespace std;
|
||||||
|
using namespace Mangle::Input;
|
||||||
|
|
||||||
|
Driver *input;
|
||||||
|
|
||||||
|
struct MyCB : Event
|
||||||
|
{
|
||||||
|
void event(Event::Type type, int i, const void *p)
|
||||||
|
{
|
||||||
|
cout << "got event: type=" << type << " index=" << i << endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void mainLoop(int argc, int quitKey)
|
||||||
|
{
|
||||||
|
cout << "Hold the Q key to quit:\n";
|
||||||
|
input->setEvent(EventPtr(new MyCB));
|
||||||
|
while(!input->isDown(quitKey))
|
||||||
|
{
|
||||||
|
input->capture();
|
||||||
|
usleep(20000);
|
||||||
|
|
||||||
|
if(argc == 1)
|
||||||
|
{
|
||||||
|
cout << "You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete input;
|
||||||
|
cout << "\nBye bye!\n";
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "../filters/eventlist.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Mangle::Input;
|
||||||
|
|
||||||
|
struct MyEvent : Event
|
||||||
|
{
|
||||||
|
int ii;
|
||||||
|
MyEvent(int i) : ii(i) {}
|
||||||
|
|
||||||
|
void event(Event::Type type, int i, const void *p)
|
||||||
|
{
|
||||||
|
cout << " #" << ii << " got event: type=" << type << " index=" << i << endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EventList lst;
|
||||||
|
|
||||||
|
int iii=1;
|
||||||
|
void make(int flags)
|
||||||
|
{
|
||||||
|
lst.add(EventPtr(new MyEvent(iii++)), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(Event::Type type)
|
||||||
|
{
|
||||||
|
cout << "Sending type " << type << endl;
|
||||||
|
lst.event(type,0,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
make(Event::EV_ALL);
|
||||||
|
make(Event::EV_KeyDown);
|
||||||
|
make(Event::EV_KeyUp | Event::EV_MouseDown);
|
||||||
|
|
||||||
|
send(Event::EV_Unknown);
|
||||||
|
send(Event::EV_KeyDown);
|
||||||
|
send(Event::EV_KeyUp);
|
||||||
|
send(Event::EV_MouseDown);
|
||||||
|
|
||||||
|
cout << "Enough of that\n";
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
#include "common.cpp"
|
||||||
|
|
||||||
|
#include "../servers/ois_driver.hpp"
|
||||||
|
#include <Ogre.h>
|
||||||
|
#include <OIS/OIS.h>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
bool isFile(const char *name)
|
||||||
|
{
|
||||||
|
boost::filesystem::path cfg_file_path(name);
|
||||||
|
return boost::filesystem::exists(cfg_file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Ogre;
|
||||||
|
using namespace OIS;
|
||||||
|
|
||||||
|
Root *root;
|
||||||
|
RenderWindow *window;
|
||||||
|
|
||||||
|
void setupOgre()
|
||||||
|
{
|
||||||
|
// Disable logging
|
||||||
|
new LogManager;
|
||||||
|
Log *log = LogManager::getSingleton().createLog("");
|
||||||
|
log->setDebugOutputEnabled(false);
|
||||||
|
|
||||||
|
bool useConfig = isFile("ogre.cfg");
|
||||||
|
|
||||||
|
// Set up Root
|
||||||
|
root = new Root("plugins.cfg", "ogre.cfg", "");
|
||||||
|
|
||||||
|
// Configure
|
||||||
|
if(!useConfig)
|
||||||
|
root->showConfigDialog();
|
||||||
|
else
|
||||||
|
root->restoreConfig();
|
||||||
|
|
||||||
|
// Initialize OGRE window
|
||||||
|
window = root->initialise(true, "test", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
setupOgre();
|
||||||
|
input = new OISDriver(window);
|
||||||
|
|
||||||
|
mainLoop(argc, KC_Q);
|
||||||
|
|
||||||
|
delete root;
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
Sending type 1
|
||||||
|
#1 got event: type=1 index=0
|
||||||
|
Sending type 2
|
||||||
|
#1 got event: type=2 index=0
|
||||||
|
#2 got event: type=2 index=0
|
||||||
|
Sending type 4
|
||||||
|
#1 got event: type=4 index=0
|
||||||
|
#3 got event: type=4 index=0
|
||||||
|
Sending type 16
|
||||||
|
#1 got event: type=16 index=0
|
||||||
|
#3 got event: type=16 index=0
|
||||||
|
Enough of that
|
@ -0,0 +1,5 @@
|
|||||||
|
Hold the Q key to quit:
|
||||||
|
got event: type=8 index=-1
|
||||||
|
You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly
|
||||||
|
|
||||||
|
Bye bye!
|
@ -0,0 +1,5 @@
|
|||||||
|
Hold the Q key to quit:
|
||||||
|
got event: type=1 index=-1
|
||||||
|
You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly
|
||||||
|
|
||||||
|
Bye bye!
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue