Merge branch 'master' into dialogue

Conflicts:
	apps/openmw/mwscript/docs/vmformat.txt
actorid
Marc Zinnschlag 13 years ago
commit 4bdfbb6d4f

3
.gitignore vendored

@ -7,6 +7,9 @@ Docs/mainpage.hpp
CMakeFiles
*/CMakeFiles
CMakeCache.txt
moc_*.cxx
cmake_install.cmake
*.[ao]
Makefile
makefile
data

@ -1,11 +1,13 @@
project(OpenMW)
IF (APPLE)
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/OpenMW.app")
if (APPLE)
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
# using 10.6 sdk
set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.6.sdk")
ENDIF (APPLE)
endif (APPLE)
# Macros
@ -16,8 +18,8 @@ include (OpenMWMacros)
# Version
set (OPENMW_VERSION_MAJOR 0)
set (OPENMW_VERSION_MINOR 11)
set (OPENMW_VERSION_RELEASE 1)
set (OPENMW_VERSION_MINOR 12)
set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
@ -94,6 +96,7 @@ source_group(libs\\mangle FILES ${MANGLE_ALL})
set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/mouselook.cpp
${LIBDIR}/openengine/ogre/fader.cpp
)
set(OENGINE_GUI
${LIBDIR}/openengine/gui/events.cpp
@ -188,9 +191,8 @@ find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED)
include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE
${OIS_INCLUDE_DIR} ${Boost_INCLUDE_DIR}
${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR}
${CMAKE_HOME_DIRECTORY}/extern/caelum/include
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/MyGUIEngine/include
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/OgrePlatform/include
${OPENAL_INCLUDE_DIR}
@ -200,7 +202,14 @@ include_directories("."
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
add_subdirectory( extern/caelum )
if(APPLE)
# List used Ogre plugins
SET(USED_OGRE_PLUGINS "RenderSystem_GL"
"Plugin_OctreeSceneManager"
"Plugin_CgProgramManager"
"Plugin_ParticleFX")
endif(APPLE)
add_subdirectory( extern/mygui_3.0.1 )
# Make sure that certain libraries are used as static libraries
@ -210,9 +219,6 @@ add_subdirectory( extern/mygui_3.0.1 )
# MyGUI: extern/mygui_3.0.0/
add_definitions(-DMYGUI_STATIC)
# Caelum: extern/caelum/
add_definitions(-DCAELUM_STATIC)
# Specify build paths
if (APPLE)
@ -243,22 +249,17 @@ if (APPLE)
"${OpenMW_BINARY_DIR}/plugins.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
"${APP_BUNDLE_DIR}/Contents/Info.plist" COPYONLY)
"${APP_BUNDLE_DIR}/Contents/Info.plist")
configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
# prepare plugins
configure_file(${OGRE_PLUGIN_DIR}/RenderSystem_GL.dylib
"${APP_BUNDLE_DIR}/Contents/Plugins/RenderSystem_GL.dylib" COPYONLY)
configure_file(${OGRE_PLUGIN_DIR}/Plugin_OctreeSceneManager.dylib
"${APP_BUNDLE_DIR}/Contents/Plugins/Plugin_OctreeSceneManager.dylib" COPYONLY)
configure_file(${OGRE_PLUGIN_DIR}/Plugin_ParticleFX.dylib
"${APP_BUNDLE_DIR}/Contents/Plugins/Plugin_ParticleFX.dylib" COPYONLY)
foreach(plugin ${USED_OGRE_PLUGINS})
configure_file("${OGRE_PLUGIN_DIR}/${plugin}.dylib"
"${APP_BUNDLE_DIR}/Contents/Plugins/${plugin}.dylib"
COPYONLY)
endforeach()
endif (APPLE)
@ -268,36 +269,6 @@ if (CMAKE_COMPILER_IS_GNUCC)
add_definitions (-Wall)
endif (CMAKE_COMPILER_IS_GNUCC)
# Apple bundling
# TODO REWRITE!
if (APPLE)
set(MISC_FILES
${APP_BUNDLE_DIR}/Contents/MacOS/openmw.cfg
${APP_BUNDLE_DIR}/Contents/MacOS/plugins.cfg)
set(OGRE_PLUGINS
${APP_BUNDLE_DIR}/Contents/Plugins/*)
install(FILES ${MISC_FILES} DESTINATION ../MacOS)
install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Plugins" DESTINATION ..)
install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Resources/resources" DESTINATION ../Resources)
set(CPACK_GENERATOR "Bundle")
set(CPACK_BUNDLE_PLIST "${CMAKE_SOURCE_DIR}/files/mac/Info.plist")
set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw.icns")
set(CPACK_BUNDLE_NAME "OpenMW")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
include(CPack)
set(CMAKE_EXE_LINKER_FLAGS "-arch i386")
set(CMAKE_CXX_FLAGS "-arch i386")
endif (APPLE)
if(DPKG_PROGRAM)
SET(CMAKE_INSTALL_PREFIX "/usr")
@ -326,7 +297,7 @@ if(DPKG_PROGRAM)
SET(CPACK_GENERATOR "DEB")
SET(CPACK_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.com")
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.org")
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PACKAGE_MAINTAINER}")
SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A reimplementation of The Elder Scrolls III: Morrowind
@ -351,6 +322,54 @@ if(DPKG_PROGRAM)
include(CPack)
endif(DPKG_PROGRAM)
if(WIN32)
FILE(GLOB files "${OpenMW_BINARY_DIR}/Release/*.*")
INSTALL(FILES ${files} DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
SET(CPACK_GENERATOR "NSIS")
SET(CPACK_PACKAGE_NAME "OpenMW")
SET(CPACK_PACKAGE_VENDOR "OpenMW.org")
SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;esmtool;Esmtool;omwlauncher;OpenMW Launcher")
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt")
SET(CPACK_RESOURCE_FILE_LICENSE "${OpenMW_SOURCE_DIR}/GPL3.txt")
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
SET(CPACK_NSIS_DISPLAY_NAME "OpenMW")
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
if(EXISTS ${VCREDIST32})
INSTALL(FILES ${VCREDIST32} DESTINATION "redist")
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x86.exe\\\" /q'" )
endif(EXISTS ${VCREDIST32})
SET(VCREDIST64 "${OpenMW_BINARY_DIR}/vcredist_x64.exe")
if(EXISTS ${VCREDIST64})
INSTALL(FILES ${VCREDIST64} DESTINATION "redist")
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x64.exe\\\" /q'" )
endif(EXISTS ${VCREDIST64})
SET(OALREDIST "${OpenMW_BINARY_DIR}/oalinst.exe")
if(EXISTS ${OALREDIST})
INSTALL(FILES ${OALREDIST} DESTINATION "redist")
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}
ExecWait '\\\"$INSTDIR\\\\redist\\\\oalinst.exe\\\" /s'" )
endif(EXISTS ${OALREDIST})
if(CMAKE_CL_64)
SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
endif()
include(CPack)
endif(WIN32)
# Components
add_subdirectory (components)
@ -405,3 +424,82 @@ if (WIN32)
#set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
#set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
endif()
# Apple bundling
if (APPLE)
set(INSTALL_SUBDIR OpenMW)
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
set(APPS "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
set(PLUGINS "")
# Scan Plugins dir for *.dylibs
set(PLUGIN_SEARCH_ROOT "${APP_BUNDLE_DIR}/Contents/Plugins")
file(GLOB_RECURSE ALL_PLUGINS "${PLUGIN_SEARCH_ROOT}/*.dylib")
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins")
foreach(PLUGIN ${ALL_PLUGINS})
string(REPLACE "${PLUGIN_SEARCH_ROOT}/" "" PLUGIN_RELATIVE "${PLUGIN}")
set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}")
endforeach()
#For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail
set(DIRS "")
# Overriding item resolving during installation, it needed if
# some library already has be "fixed up", i.e. its id name contains @executable_path,
# but library is not embedded in bundle. For example, it's Ogre.framework from Ogre SDK.
# Current implementation of GetPrerequsities/BundleUtilities doesn't handle that case.
#
# Current limitations:
# 1. Handles only frameworks, not simple libs
INSTALL(CODE "
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH})
set(OPENMW_RESOLVED_ITEMS \"\")
function(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var)
if(item MATCHES \"@executable_path\" AND NOT \${\${resolved_var}})
if (item MATCHES \"Frameworks\") # if it is a framework
# get last segment of path
get_filename_component(fname \"\${item}\" NAME_WE)
find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /Library/Frameworks)
if (ri)
message(STATUS \"found \${ri} for \${item}\")
string(REGEX REPLACE \"^.*/Frameworks/.*\\\\.framework\" \"\" item_part \${item})
set(ri \"\${ri}\${item_part}\")
set(\${resolved_item_var} \${ri} PARENT_SCOPE)
set(\${resolved_var} 1 PARENT_SCOPE)
set(OPENMW_RESOLVED_ITEMS \${_OPENMW_RESOLVED_ITEMS} \${ri})
endif()
else()
# code path for standard (non-framework) libs (ogre & qt pugins)
endif()
endif()
endfunction(gp_resolve_item_override)
cmake_policy(SET CMP0009 OLD)
set(BU_CHMOD_BUNDLE_ITEMS ON)
include(BundleUtilities)
fixup_bundle(\"${APPS}\" \"${PLUGINS}\" \"${DIRS}\")
" COMPONENT Runtime)
include(CPack)
set(CMAKE_EXE_LINKER_FLAGS "-arch i386")
set(CMAKE_CXX_FLAGS "-arch i386")
endif (APPLE)

@ -1,6 +1,4 @@
set(ESMTOOL
esmtool_cmd.c
esmtool_cmd.h
esmtool.cpp
)
source_group(apps\\esmtool FILES ${ESMTOOL})

@ -1,35 +1,138 @@
#include <iostream>
#include <boost/program_options.hpp>
#include <components/esm/esm_reader.hpp>
#include <components/esm/records.hpp>
#include "esmtool_cmd.h"
#include <iostream>
#define ESMTOOL_VERSION 1.1
using namespace std;
using namespace ESM;
// Create a local alias for brevity
namespace bpo = boost::program_options;
void printRaw(ESMReader &esm);
void loadCell(Cell &cell, ESMReader &esm, bool quiet);
int main(int argc, char**argv)
// Based on the legacy struct
struct Arguments
{
gengetopt_args_info info;
unsigned int raw_given;
unsigned int quiet_given;
unsigned int loadcells_given;
std::string encoding;
std::string filename;
};
if(cmdline_parser(argc, argv, &info) != 0)
return 1;
bool parseOptions (int argc, char** argv, Arguments &info)
{
bpo::options_description desc("Inspect and extract from Morrowind ES files (ESM, ESP, ESS)\nSyntax: esmtool [options] file \nAllowed options");
desc.add_options()
("help,h", "print help message.")
("version,v", "print version information and quit.")
("raw,r", "Show an unformattet list of all records and subrecords.")
("quiet,q", "Supress all record information. Useful for speed tests.")
("loadcells,C", "Browse through contents of all cells.")
( "encoding,e", bpo::value<std::string>(&(info.encoding))->
default_value("win1252"),
"Character encoding used in ESMTool:\n"
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
"\n\twin1252 - Western European (Latin) alphabet, used by default")
;
std::string finalText = "\nIf no option is given, the default action is to parse all records in the archive\nand display diagnostic information.";
if(info.inputs_num != 1)
// input-file is hidden and used as a positional argument
bpo::options_description hidden("Hidden Options");
hidden.add_options()
( "input-file,i", bpo::value< vector<std::string> >(), "input file")
;
bpo::positional_options_description p;
p.add("input-file", -1);
// there might be a better way to do this
bpo::options_description all;
all.add(desc).add(hidden);
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
.options(all).positional(p).run();
bpo::variables_map variables;
bpo::store(valid_opts, variables);
bpo::notify(variables);
if (variables.count ("help"))
{
if(info.inputs_num == 0)
cout << "ERROR: missing ES file\n\n";
else
cout << "ERROR: more than one ES file specified\n\n";
cmdline_parser_print_help();
return 1;
std::cout << desc << finalText << std::endl;
return false;
}
if (variables.count ("version"))
{
std::cout << "ESMTool version " << ESMTOOL_VERSION << std::endl;
return false;
}
if ( !variables.count("input-file") )
{
std::cout << "\nERROR: missing ES file\n\n";
std::cout << desc << finalText << std::endl;
return false;
}
// handling gracefully the user adding multiple files
if (variables["input-file"].as< vector<std::string> >().size() > 1)
{
std::cout << "\nERROR: more than one ES file specified\n\n";
std::cout << desc << finalText << std::endl;
return false;
}
info.filename = variables["input-file"].as< vector<std::string> >()[0];
info.raw_given = variables.count ("raw");
info.quiet_given = variables.count ("quiet");
info.loadcells_given = variables.count ("loadcells");
// Font encoding settings
info.encoding = variables["encoding"].as<std::string>();
if (info.encoding == "win1250")
{
std::cout << "Using Central and Eastern European font encoding." << std::endl;
}
else if (info.encoding == "win1251")
{
std::cout << "Using Cyrillic font encoding." << std::endl;
}
else
{
if(info.encoding != "win1252")
{
std::cout << info.encoding << " is not a valid encoding option." << std::endl;
info.encoding = "win1252";
}
std::cout << "Using default (English) font encoding." << std::endl;
}
return true;
}
int main(int argc, char**argv)
{
Arguments info;
if(!parseOptions (argc, argv, info))
return 1;
ESMReader esm;
const char* filename = info.inputs[0];
esm.setEncoding(info.encoding);
string filename = info.filename;
cout << "\nFile: " << filename << endl;
try {

@ -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 */

@ -41,8 +41,10 @@ source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC
find_package(Qt4 REQUIRED)
set(QT_USE_QTGUI 1)
find_package(PNG REQUIRED)
include_directories(${PNG_INCLUDE_DIR})
if (NOT APPLE) # this dependency can be completely removed, but now it only tested on OS X
find_package(PNG REQUIRED)
include_directories(${PNG_INCLUDE_DIR})
endif()
QT4_ADD_RESOURCES(RCC_SRCS resources.qrc)
QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
@ -71,9 +73,13 @@ endif()
if (APPLE)
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
"${APP_BUNDLE_DIR}/../launcher.qss")
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
"${APP_BUNDLE_DIR}/../launcher.cfg")
else()
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources/launcher.qss")
# Fallback in case getGlobalDataPath does not point to resources
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")

@ -3,7 +3,7 @@
#include <components/esm/esm_reader.hpp>
#include <components/files/collections.hpp>
#include <components/files/multidircollection.hpp>
#include <components/cfg/configurationmanager.hpp>
#include <components/files/configurationmanager.hpp>
#include "datafilespage.hpp"
#include "lineedit.hpp"
@ -26,7 +26,9 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2)
return index1.row() <= index2.row();
}
DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent)
: QWidget(parent)
, mCfgMgr(cfg)
{
mDataFilesModel = new QStandardItemModel(); // Contains all plugins with masters
mPluginsModel = new PluginsModel(); // Contains selectable plugins
@ -121,23 +123,88 @@ DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
setupConfig();
setupDataFiles();
createActions();
}
void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
void DataFilesPage::setupConfig()
{
// Put the paths in a boost::filesystem vector to use with Files::Collections
Files::PathContainer dataDirs;
QString config = QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.cfg").string());
QFile file(config);
if (!file.exists()) {
config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string());
}
// Open our config file
mLauncherConfig = new QSettings(config, QSettings::IniFormat);
mLauncherConfig->sync();
// Make sure we have no groups open
while (!mLauncherConfig->group().isEmpty()) {
mLauncherConfig->endGroup();
}
mLauncherConfig->beginGroup("Profiles");
QStringList profiles = mLauncherConfig->childGroups();
foreach (const QString &currentPath, paths) {
dataDirs.push_back(boost::filesystem::path(currentPath.toStdString()));
if (profiles.isEmpty()) {
// Add a default profile
profiles.append("Default");
}
mProfilesComboBox->addItems(profiles);
QString currentProfile = mLauncherConfig->value("CurrentProfile").toString();
if (currentProfile.isEmpty()) {
// No current profile selected
currentProfile = "Default";
}
mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(currentProfile));
mLauncherConfig->endGroup();
// Now we connect the combobox to do something if the profile changes
// This prevents strange behaviour while reading and appending the profiles
connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&)));
}
void DataFilesPage::setupDataFiles()
{
// We use the Configuration Manager to retrieve the configuration values
boost::program_options::variables_map variables;
boost::program_options::options_description desc;
desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
// ("data-local", boost::program_options::value<std::string>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
mCfgMgr.readConfiguration(variables, desc);
// Put the paths in a boost::filesystem vector to use with Files::Collections
Files::PathContainer dataDirs(variables["data"].as<Files::PathContainer>());
// std::string local(variables["data-local"].as<std::string>());
// if (!local.empty())
// {
// dataDirs.push_back(Files::PathContainer::value_type(local));
// }
if (dataDirs.size()>1)
dataDirs.resize (1);
mCfgMgr.processPaths(dataDirs);
// Create a file collection for the dataDirs
Files::Collections mFileCollections(dataDirs, strict);
Files::Collections fileCollections(dataDirs, !variables["fs-strict"].as<bool>());
// First we add all the master files
const Files::MultiDirCollection &esm = mFileCollections.getCollection(".esm");
const Files::MultiDirCollection &esm = fileCollections.getCollection(".esm");
unsigned int i = 0; // Row number
for (Files::MultiDirCollection::TIter iter(esm.begin()); iter!=esm.end(); ++iter)
@ -157,14 +224,14 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
}
// Now on to the plugins
const Files::MultiDirCollection &esp = mFileCollections.getCollection(".esp");
const Files::MultiDirCollection &esp = fileCollections.getCollection(".esp");
for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter)
{
ESMReader fileReader;
QStringList availableMasters; // Will contain all found masters
fileReader.setEncoding("win1252"); // FIXME: This should be configurable!
fileReader.setEncoding(variables["encoding"].as<std::string>());
fileReader.open(iter->second.string());
// First we fill the availableMasters and the mMastersWidget
@ -234,54 +301,6 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
readConfig();
}
void DataFilesPage::setupConfig()
{
Cfg::ConfigurationManager cfg;
QString config = (cfg.getRuntimeConfigPath() / "launcher.cfg").string().c_str();
QFile file(config);
if (!file.exists()) {
config = QString::fromStdString((cfg.getLocalConfigPath() / "launcher.cfg").string());
}
file.setFileName(config); // Just for displaying information
// Open our config file
mLauncherConfig = new QSettings(config, QSettings::IniFormat);
mLauncherConfig->sync();
// Make sure we have no groups open
while (!mLauncherConfig->group().isEmpty()) {
mLauncherConfig->endGroup();
}
mLauncherConfig->beginGroup("Profiles");
QStringList profiles = mLauncherConfig->childGroups();
if (profiles.isEmpty()) {
// Add a default profile
profiles.append("Default");
}
mProfilesComboBox->addItems(profiles);
QString currentProfile = mLauncherConfig->value("CurrentProfile").toString();
if (currentProfile.isEmpty()) {
// No current profile selected
currentProfile = "Default";
}
mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(currentProfile));
mLauncherConfig->endGroup();
// Now we connect the combobox to do something if the profile changes
// This prevents strange behaviour while reading and appending the profiles
connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&)));
}
void DataFilesPage::createActions()
{
// Refresh the plugins
@ -968,8 +987,8 @@ void DataFilesPage::readConfig()
void DataFilesPage::writeConfig(QString profile)
{
// Don't overwrite the config if no plugins are found
if (mPluginsModel->rowCount() < 1) {
// Don't overwrite the config if no masters are found
if (mMastersWidget->rowCount() < 1) {
return;
}
@ -981,6 +1000,61 @@ void DataFilesPage::writeConfig(QString profile)
return;
}
// Prepare the OpenMW config
QString config = QString::fromStdString((mCfgMgr.getLocalPath() / "openmw.cfg").string());
QFile file(config);
if (!file.exists()) {
config = QString::fromStdString((mCfgMgr.getUserPath() / "openmw.cfg").string());
}
// Open the config as a QFile
file.setFileName(config);
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle("Error writing OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not open or create %0</b><br><br> \
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
msgBox.exec();
qApp->exit(1);
return;
}
QTextStream in(&file);
QByteArray buffer;
// Remove all previous master/plugin entries from config
while (!in.atEnd()) {
QString line = in.readLine();
if (!line.contains("master") && !line.contains("plugin")) {
buffer += line += "\n";
}
}
file.close();
// Now we write back the other config entries
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
QMessageBox msgBox;
msgBox.setWindowTitle("Error writing OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not write to %0</b><br><br> \
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
msgBox.exec();
qApp->exit(1);
return;
}
file.write(buffer);
QTextStream gameConfig(&file);
// Make sure we have no groups open
while (!mLauncherConfig->group().isEmpty()) {
mLauncherConfig->endGroup();
@ -993,13 +1067,16 @@ void DataFilesPage::writeConfig(QString profile)
mLauncherConfig->beginGroup(profile);
mLauncherConfig->remove(""); // Clear the subgroup
// First write the masters to the config
const QStringList masterList = selectedMasters();
// First write the masters to the configs
const QStringList masters = selectedMasters();
// We don't use foreach because we need i
for (int i = 0; i < masterList.size(); ++i) {
const QString master = masterList.at(i);
mLauncherConfig->setValue(QString("Master%0").arg(i), master);
for (int i = 0; i < masters.size(); ++i) {
const QString currentMaster = masters.at(i);
mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster);
gameConfig << "master=" << currentMaster << endl;
}
// Now write all checked plugins
@ -1007,10 +1084,13 @@ void DataFilesPage::writeConfig(QString profile)
for (int i = 0; i < plugins.size(); ++i)
{
mLauncherConfig->setValue(QString("Plugin%1").arg(i), plugins.at(i));
const QString currentPlugin = plugins.at(i);
mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin);
gameConfig << "plugin=" << currentPlugin << endl;
}
file.close();
mLauncherConfig->endGroup();
mLauncherConfig->endGroup();
mLauncherConfig->sync();
}

@ -19,24 +19,19 @@ class PluginsModel;
class PluginsView;
class ComboBox;
namespace Files { struct ConfigurationManager; }
class DataFilesPage : public QWidget
{
Q_OBJECT
public:
DataFilesPage(QWidget *parent = 0);
DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0);
ComboBox *mProfilesComboBox;
QSettings *mLauncherConfig;
const QStringList checkedPlugins();
const QStringList selectedMasters();
void setupConfig();
void readConfig();
void writeConfig(QString profile = QString());
void setupDataFiles(const QStringList &paths, bool strict);
public slots:
void masterSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void setCheckState(QModelIndex index);
@ -81,11 +76,20 @@ private:
QAction *mCheckAction;
QAction *mUncheckAction;
Files::ConfigurationManager &mCfgMgr;
QSettings *mLauncherConfig;
const QStringList checkedPlugins();
const QStringList selectedMasters();
void addPlugins(const QModelIndex &index);
void removePlugins(const QModelIndex &index);
void uncheckPlugins();
void createActions();
void setupDataFiles();
void setupConfig();
void readConfig();
void scrollToSelection();
};

@ -1,8 +1,11 @@
#include <QtGui>
#include "graphicspage.hpp"
#include <components/files/configurationmanager.hpp>
GraphicsPage::GraphicsPage(QWidget *parent) : QWidget(parent)
GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent)
: QWidget(parent)
, mCfgMgr(cfg)
{
QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this);
@ -147,21 +150,21 @@ void GraphicsPage::createPages()
void GraphicsPage::setupConfig()
{
QString ogreCfg = mCfg.getOgreConfigPath().string().c_str();
QString ogreCfg = mCfgMgr.getOgreConfigPath().string().c_str();
QFile file(ogreCfg);
mOgreConfig = new QSettings(ogreCfg, QSettings::IniFormat);
}
void GraphicsPage::setupOgre()
{
QString pluginCfg = mCfg.getPluginsConfigPath().string().c_str();
QString pluginCfg = mCfgMgr.getPluginsConfigPath().string().c_str();
QFile file(pluginCfg);
// Create a log manager so we can surpress debug text to stdout/stderr
Ogre::LogManager* logMgr = OGRE_NEW Ogre::LogManager;
logMgr->createLog((mCfg.getLogPath().string() + "/launcherOgre.log"), true, false, false);
logMgr->createLog((mCfgMgr.getLogPath().string() + "/launcherOgre.log"), true, false, false);
QString ogreCfg = QString::fromStdString(mCfg.getOgreConfigPath().string());
QString ogreCfg = QString::fromStdString(mCfgMgr.getOgreConfigPath().string());
file.setFileName(ogreCfg);
//we need to check that the path to the configuration file exists before we
@ -177,7 +180,7 @@ void GraphicsPage::setupOgre()
Make sure you have write access to<br>%1<br><br>")).arg(configDir.path()));
msgBox.exec();
QApplication::exit(1);
qApp->exit(1);
return;
}
@ -200,7 +203,7 @@ void GraphicsPage::setupOgre()
qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError));
QApplication::exit(1);
qApp->exit(1);
return;
}
@ -234,7 +237,7 @@ void GraphicsPage::setupOgre()
Please make sure the plugins.cfg file exists and contains a valid rendering plugin.<br>"));
msgBox.exec();
QApplication::exit(1);
qApp->exit(1);
return;
}
@ -420,7 +423,7 @@ void GraphicsPage::writeConfig()
qCritical("Error validating configuration");
QApplication::exit(1);
qApp->exit(1);
return;
}
@ -446,7 +449,8 @@ void GraphicsPage::writeConfig()
qCritical("Error saving Ogre configuration, the error reported was:\n %s", qPrintable(ogreError));
QApplication::exit(1);
qApp->exit(1);
return;
}
}

@ -7,21 +7,20 @@
#include <OgreRenderSystem.h>
#include <OgreConfigFile.h>
#include <OgreConfigDialog.h>
#include <components/cfg/configurationmanager.hpp>
class QComboBox;
class QCheckBox;
class QStackedWidget;
class QSettings;
namespace Files { struct ConfigurationManager; }
class GraphicsPage : public QWidget
{
Q_OBJECT
public:
GraphicsPage(QWidget *parent = 0);
QSettings *mOgreConfig;
GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent = 0);
void writeConfig();
@ -29,7 +28,6 @@ public slots:
void rendererChanged(const QString &renderer);
private:
Cfg::ConfigurationManager mCfg;
Ogre::Root *mOgre;
Ogre::RenderSystem *mSelectedRenderSystem;
Ogre::RenderSystem *mOpenGLRenderSystem;
@ -59,6 +57,10 @@ private:
QCheckBox *mD3DVSyncCheckBox;
QCheckBox *mD3DFullScreenCheckBox;
QSettings *mOgreConfig;
Files::ConfigurationManager &mCfgMgr;
QString getConfigValue(const QString &key, Ogre::RenderSystem *renderer);
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);

@ -1,6 +1,7 @@
#include <QApplication>
#include <QDir>
#include <QFile>
#include <QtDebug>
#include "maindialog.hpp"
@ -17,16 +18,18 @@ int main(int argc, char *argv[])
dir.cdUp();
dir.cdUp();
}
#endif
QDir::setCurrent(dir.absolutePath());
// force Qt to load only LOCAL plugins, don't touch system Qt installation
QDir pluginsPath(QCoreApplication::applicationDirPath());
pluginsPath.cdUp();
pluginsPath.cd("Plugins");
// Load the stylesheet
QFile file("./launcher.qss");
QStringList libraryPaths;
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
app.setLibraryPaths(libraryPaths);
#endif
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
app.setStyleSheet(styleSheet);
QDir::setCurrent(dir.absolutePath());
MainDialog dialog;
return dialog.exec();

@ -45,6 +45,20 @@ MainDialog::MainDialog()
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
setMinimumSize(QSize(575, 575));
// Load the stylesheet
QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string());
QFile file(config);
if (!file.exists()) {
file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string()));
}
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
qApp->setStyleSheet(styleSheet);
file.close();
connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(play()));
@ -85,116 +99,13 @@ void MainDialog::createIcons()
}
QStringList MainDialog::readConfig(const QString &fileName)
{
// We can't use QSettings directly because it
// does not support multiple keys with the same name
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox msgBox;
msgBox.setWindowTitle("Error opening OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not open %0</b><br><br> \
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
msgBox.exec();
QApplication::exit(); // File cannot be opened or created
}
QTextStream in(&file);
QStringList dataDirs;
QString dataLocal;
// Read the config line by line
while (!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith("data=")) {
dataDirs.append(line.remove("data="));
}
// Read the data-local key, if more than one are found only the last is used
if (line.startsWith("data-local=")) {
dataLocal = line.remove("data-local=");
}
// Read fs-strict key
if (line.startsWith("fs-strict=")) {
QString value = line.remove("fs-strict=");
(value.toLower() == QLatin1String("true"))
? mStrict = true
: mStrict = false;
}
}
// Add the data-local= key to the end of the dataDirs for priority reasons
if (!dataLocal.isEmpty()) {
dataDirs.append(dataLocal);
}
if (!dataDirs.isEmpty())
{
// Reset the global datadirs to the newly read entries
// Else return the previous dataDirs because nothing was found in this file;
mDataDirs = dataDirs;
}
file.close();
return mDataDirs;
}
void MainDialog::createPages()
{
mPlayPage = new PlayPage(this);
mGraphicsPage = new GraphicsPage(this);
mDataFilesPage = new DataFilesPage(this);
// Retrieve all data entries from the configs
QStringList dataDirs;
mGraphicsPage = new GraphicsPage(mCfgMgr, this);
mDataFilesPage = new DataFilesPage(mCfgMgr, this);
// Global location
QFile file(QString::fromStdString((mCfg.getGlobalConfigPath()/"openmw.cfg").string()));
if (file.exists()) {
dataDirs = readConfig(file.fileName());
}
// User location
file.setFileName(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string()));
if (file.exists()) {
dataDirs = readConfig(file.fileName());
}
// Local location
file.setFileName("./openmw.cfg");
if (file.exists()) {
dataDirs = readConfig(file.fileName());
}
file.close();
if (!dataDirs.isEmpty()) {
// Now pass the datadirs on to the DataFilesPage
mDataFilesPage->setupDataFiles(dataDirs, mStrict);
} else {
QMessageBox msgBox;
msgBox.setWindowTitle("Error reading OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not read the location of the data files</b><br><br> \
Please make sure OpenMW is correctly configured and try again.<br>"));
msgBox.exec();
QApplication::exit(); // No data or data-local entries in openmw.cfg
}
// Set the combobox of the play page to imitate the comobox on the datafilespage
// Set the combobox of the play page to imitate the combobox on the datafilespage
mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model());
mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex());
@ -246,14 +157,16 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
void MainDialog::closeEvent(QCloseEvent *event)
{
// Now write all config files
writeConfig();
mDataFilesPage->writeConfig();
mGraphicsPage->writeConfig();
event->accept();
}
void MainDialog::play()
{
// First do a write of all the configs, just to be sure
writeConfig();
mDataFilesPage->writeConfig();
mGraphicsPage->writeConfig();
#ifdef Q_WS_WIN
QString game = "./openmw.exe";
@ -313,75 +226,3 @@ void MainDialog::play()
close();
}
}
void MainDialog::writeConfig()
{
// Write the profiles
mDataFilesPage->writeConfig();
mDataFilesPage->mLauncherConfig->sync();
// Write the graphics settings
mGraphicsPage->writeConfig();
mGraphicsPage->mOgreConfig->sync();
QStringList dataFiles = mDataFilesPage->selectedMasters();
dataFiles.append(mDataFilesPage->checkedPlugins());
// Open the config as a QFile
QFile file(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string()));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle("Error writing OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not open or create %0</b><br><br> \
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
msgBox.exec();
QApplication::exit(1);
}
QTextStream in(&file);
QByteArray buffer;
// Remove all previous master/plugin entries from config
while (!in.atEnd()) {
QString line = in.readLine();
if (!line.contains("master") && !line.contains("plugin")) {
buffer += line += "\n";
}
}
file.close();
// Now we write back the other config entries
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
QMessageBox msgBox;
msgBox.setWindowTitle("Error writing OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not write to %0</b><br><br> \
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
msgBox.exec();
QApplication::exit(1);
}
file.write(buffer);
QTextStream out(&file);
// Write the list of game files to the config
foreach (const QString &currentFile, dataFiles) {
if (currentFile.endsWith(QString(".esm"), Qt::CaseInsensitive)) {
out << "master=" << currentFile << endl;
} else if (currentFile.endsWith(QString(".esp"), Qt::CaseInsensitive)) {
out << "plugin=" << currentFile << endl;
}
}
file.close();
}

@ -3,7 +3,7 @@
#include <QDialog>
#include <components/cfg/configurationmanager.hpp>
#include <components/files/configurationmanager.hpp>
class QListWidget;
class QListWidgetItem;
@ -28,15 +28,11 @@ public slots:
void play();
void profileChanged(int index);
private:
void createIcons();
void createPages();
void writeConfig();
void closeEvent(QCloseEvent *event);
QStringList readConfig(const QString &fileName);
QListWidget *mIconWidget;
QStackedWidget *mPagesWidget;
@ -44,10 +40,7 @@ private:
GraphicsPage *mGraphicsPage;
DataFilesPage *mDataFilesPage;
QStringList mDataDirs;
bool mStrict;
Cfg::ConfigurationManager mCfg;
Files::ConfigurationManager mCfgMgr;
};
#endif

@ -43,8 +43,8 @@ add_openmw_dir (mwsound
add_openmw_dir (mwworld
refdata world physicssystem scene environment globals class action nullaction actionteleport
containerstore actiontalk actiontake containerstore manualref containerutil player cellfunctors
cells localscripts customdata
containerstore actiontalk actiontake manualref player cellfunctors
cells localscripts customdata weather
)
add_openmw_dir (mwclass
@ -77,7 +77,6 @@ target_link_libraries(openmw
${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY}
${BULLET_LIBRARIES}
caelum
components
MyGUIEngine
MyGUIOgrePlatform
@ -86,10 +85,6 @@ target_link_libraries(openmw
if(APPLE)
find_library(CARBON_FRAMEWORK Carbon)
target_link_libraries(openmw ${CARBON_FRAMEWORK})
install(TARGETS openmw
BUNDLE DESTINATION .
RUNTIME DESTINATION ../MacOS
COMPONENT Runtime)
endif(APPLE)
if(DPKG_PROGRAM)

@ -18,7 +18,9 @@
#include <components/esm_store/cell_store.hpp>
#include <components/bsa/bsa_archive.hpp>
#include <components/esm/esm_reader.hpp>
#include <components/files/path.hpp>
#include <components/files/fixedpath.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/nifbullet/bullet_nif_loader.hpp>
#include <components/nifogre/ogre_nif_loader.hpp>
@ -171,7 +173,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
return true;
}
OMW::Engine::Engine(Cfg::ConfigurationManager& configurationManager)
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
: mOgre (0)
, mFpsLevel(0)
, mDebug (false)
@ -208,15 +210,16 @@ OMW::Engine::~Engine()
void OMW::Engine::loadBSA()
{
const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa");
for (Files::MultiDirCollection::TIter iter (bsa.begin()); iter!=bsa.end(); ++iter)
std::string dataDirectory;
for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter)
{
std::cout << "Adding " << iter->second.string() << std::endl;
Bsa::addBSA (iter->second.string());
}
std::cout << "Adding " << iter->second.string() << std::endl;
Bsa::addBSA(iter->second.string());
std::cout << "Data dir " << mDataDir.string() << std::endl;
Bsa::addDir(mDataDir.string(), mFSStrict);
dataDirectory = iter->second.parent_path().string();
std::cout << "Data dir " << dataDirectory << std::endl;
Bsa::addDir(dataDirectory, mFSStrict);
}
}
// add resources directory
@ -237,9 +240,7 @@ void OMW::Engine::enableFSStrict(bool fsStrict)
void OMW::Engine::setDataDirs (const Files::PathContainer& dataDirs)
{
/// \todo remove mDataDir, once resources system can handle multiple directories
assert (!dataDirs.empty());
mDataDir = dataDirs.back();
mDataDirs = dataDirs;
mFileCollections = Files::Collections (dataDirs, !mFSStrict);
}
@ -315,7 +316,7 @@ void OMW::Engine::go()
}
mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()),
mCfgMgr.getOgreConfigPath().string(),
mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getLogPath().string(),
mCfgMgr.getPluginsConfigPath().string(), false);
// This has to be added BEFORE MyGUI is initialized, as it needs
@ -341,7 +342,7 @@ void OMW::Engine::go()
mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(),
mOgre->getCamera(),
mEnvironment.mWorld->getStore(),
(mDataDir),
mDataDirs,
mUseSound, mFSStrict, mEnvironment);
// Create script system
@ -445,6 +446,28 @@ void OMW::Engine::activate()
}
}
void OMW::Engine::screenshot()
{
// Count screenshots.
int shotCount = 0;
const std::string screenshotPath = mCfgMgr.getUserPath().string();
// Find the first unused filename with a do-while
std::ostringstream stream;
do
{
// Reset the stream
stream.str("");
stream.clear();
stream << screenshotPath << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << ".png";
} while (boost::filesystem::exists(stream.str()));
mOgre->screenshot(stream.str());
}
void OMW::Engine::setCompileAll (bool all)
{
mCompileAll = all;

@ -9,7 +9,6 @@
#include <components/compiler/extensions.hpp>
#include <components/files/collections.hpp>
#include <components/cfg/configurationmanager.hpp>
#include "mwworld/environment.hpp"
#include "mwworld/ptr.hpp"
@ -52,13 +51,18 @@ namespace OEngine
}
}
namespace Files
{
struct ConfigurationManager;
}
namespace OMW
{
/// \brief Main engine class, that brings together all the components of OpenMW
class Engine : private Ogre::FrameListener
{
std::string mEncoding;
boost::filesystem::path mDataDir;
Files::PathContainer mDataDirs;
boost::filesystem::path mResDir;
OEngine::Render::OgreRenderer *mOgre;
std::string mCellName;
@ -101,7 +105,7 @@ namespace OMW
virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt);
public:
Engine(Cfg::ConfigurationManager& configurationManager);
Engine(Files::ConfigurationManager& configurationManager);
virtual ~Engine();
/// Enable strict filesystem mode (do not fold case)
@ -149,6 +153,9 @@ namespace OMW
/// Activate the focussed object.
void activate();
/// Write screenshot to file.
void screenshot();
/// Compile all scripts (excludign dialogue scripts) at startup?
void setCompileAll (bool all);
@ -158,7 +165,7 @@ namespace OMW
void setAnimationVerbose(bool animverbose);
private:
Cfg::ConfigurationManager& mCfgMgr;
Files::ConfigurationManager& mCfgMgr;
};
}

@ -6,9 +6,9 @@
#include <boost/program_options.hpp>
#include <components/files/fileops.hpp>
#include <components/files/path.hpp>
#include <components/files/fixedpath.hpp>
#include <components/files/collections.hpp>
#include <components/cfg/configurationmanager.hpp>
#include <components/files/configurationmanager.hpp>
#include "engine.hpp"
@ -35,6 +35,23 @@
#include "config.hpp"
#include <boost/version.hpp>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
#if (BOOST_VERSION <= 104600)
namespace boost
{
template<>
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
{
return boost::filesystem::path(arg);
}
} /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */
using namespace std;
/**
@ -46,7 +63,7 @@ using namespace std;
* \retval true - Everything goes OK
* \retval false - Error
*/
bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::ConfigurationManager& cfgMgr)
bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::ConfigurationManager& cfgMgr)
{
// Create a local alias for brevity
namespace bpo = boost::program_options;
@ -164,14 +181,19 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::Configuratio
std::string local(variables["data-local"].as<std::string>());
if (!local.empty())
{
dataDirs.push_back(Files::PathContainer::value_type(local));
std::cout << "Ignoring data-local (currently not supported)" << std::endl;
// dataDirs.push_back(Files::PathContainer::value_type(local));
}
if (dataDirs.empty())
if (dataDirs.size()>1)
{
dataDirs.push_back(cfgMgr.getLocalDataPath());
dataDirs.resize (1);
std::cout << "Ignoring all but the first data path (multiple data paths currently not supported)"
<< std::endl;
}
cfgMgr.processPaths(dataDirs);
engine.setDataDirs(dataDirs);
engine.setResourceDir(variables["resources"].as<std::string>());
@ -224,7 +246,7 @@ int main(int argc, char**argv)
try
{
Cfg::ConfigurationManager cfgMgr;
Files::ConfigurationManager cfgMgr;
OMW::Engine engine(cfgMgr);
if (parseOptions(argc, argv, engine, cfgMgr))

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -59,12 +57,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Apparatus::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.appas);
}
std::string Apparatus::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Apparatus, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -71,12 +69,6 @@ namespace MWClass
return ref->base->data.health;
}
void Armor::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.armors);
}
std::string Armor::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Armor, MWWorld::RefData> *ref =

@ -28,10 +28,6 @@ namespace MWClass
virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const;
///< Return item max health or throw an exception, if class does not have item health
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Book::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -61,12 +59,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Book::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.books);
}
std::string Book::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Book, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -59,12 +57,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Clothing::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.clothes);
}
std::string Clothing::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -6,16 +6,20 @@
#include <components/esm_store/cell_store.hpp>
#include "../mwworld/ptr.hpp"
#include "../mwworld/nullaction.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwworld/environment.hpp"
#include "../mwrender/objects.hpp"
#include "../mwsound/soundmanager.hpp"
namespace
{
struct CustomData : public MWWorld::CustomData
{
MWWorld::ContainerStore<MWWorld::RefData> mContainerStore;
MWWorld::ContainerStore mContainerStore;
virtual MWWorld::CustomData *clone() const;
};
@ -71,6 +75,38 @@ namespace MWClass
}
boost::shared_ptr<MWWorld::Action> Container::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
const std::string lockedSound = "LockedChest";
const std::string trapActivationSound = "Disarm Trap Fail";
if (ptr.getCellRef().lockLevel>0)
{
// TODO check for key
std::cout << "Locked container" << std::endl;
environment.mSoundManager->playSound(lockedSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
else
{
std::cout << "Unlocked container" << std::endl;
if(ptr.getCellRef().trap.empty())
{
// Not trapped, Inventory GUI goes here
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
else
{
// Trap activation goes here
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
environment.mSoundManager->playSound(trapActivationSound, 1.0, 1.0);
ptr.getCellRef().trap = "";
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
}
}
std::string Container::getName (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Container, MWWorld::RefData> *ref =
@ -79,7 +115,7 @@ namespace MWClass
return ref->base->name;
}
MWWorld::ContainerStore<MWWorld::RefData>& Container::getContainerStore (const MWWorld::Ptr& ptr)
MWWorld::ContainerStore& Container::getContainerStore (const MWWorld::Ptr& ptr)
const
{
ensureCustomData (ptr);

@ -20,8 +20,11 @@ namespace MWClass
///< \return name (the one that is to be presented to the user; not the internal one);
/// can return an empty string.
virtual MWWorld::ContainerStore<MWWorld::RefData>& getContainerStore (
const MWWorld::Ptr& ptr) const;
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const;
///< Return container store
virtual std::string getScript (const MWWorld::Ptr& ptr) const;

@ -1,28 +0,0 @@
#ifndef GAME_MWCLASS_CONTAINERUTIL_H
#define GAME_MWCLASS_CONTAINERUTIL_H
#include <components/esm_store/cell_store.hpp>
#include "../mwworld/ptr.hpp"
#include "../mwworld/containerstore.hpp"
namespace MWClass
{
template<typename T>
void insertIntoContainerStore (const MWWorld::Ptr& ptr,
ESMS::CellRefList<T, MWWorld::RefData>& containerStore)
{
if (!ptr.isEmpty())
{
// TODO check stacking
ESMS::LiveCellRef<T, MWWorld::RefData> cellRef(ptr.getCellRef(), ptr.get<T>()->base);
cellRef.mData = ptr.getRefData();
containerStore.list.push_back (cellRef);
}
}
}
#endif

@ -17,7 +17,7 @@ namespace
struct CustomData : public MWWorld::CustomData
{
MWMechanics::CreatureStats mCreatureStats;
MWWorld::ContainerStore<MWWorld::RefData> mContainerStore;
MWWorld::ContainerStore mContainerStore;
virtual MWWorld::CustomData *clone() const;
};
@ -118,7 +118,7 @@ namespace MWClass
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
}
MWWorld::ContainerStore<MWWorld::RefData>& Creature::getContainerStore (const MWWorld::Ptr& ptr)
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr)
const
{
ensureCustomData (ptr);

@ -39,7 +39,7 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual MWWorld::ContainerStore<MWWorld::RefData>& getContainerStore (
virtual MWWorld::ContainerStore& getContainerStore (
const MWWorld::Ptr& ptr) const;
///< Return container store

@ -14,6 +14,8 @@
#include "../mwrender/objects.hpp"
#include "../mwsound/soundmanager.hpp"
namespace MWClass
{
void Door::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -61,15 +63,28 @@ namespace MWClass
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =
ptr.get<ESM::Door>();
const std::string &openSound = ref->base->openSound;
//const std::string &closeSound = ref->base->closeSound;
const std::string lockedSound = "LockedDoor";
const std::string trapActivationSound = "Disarm Trap Fail";
if (ptr.getCellRef().lockLevel>0)
{
// TODO check for key
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
std::cout << "Locked!" << std::endl;
environment.mSoundManager->playSound(lockedSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
// TODO check trap
if(!ptr.getCellRef().trap.empty())
{
// Trap activation
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
environment.mSoundManager->playSound(trapActivationSound, 1.0, 1.0);
ptr.getCellRef().trap = "";
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
if (ref->ref.teleport)
{
@ -77,6 +92,7 @@ namespace MWClass
if (environment.mWorld->getPlayer().getPlayer()==actor)
{
// the player is using the door
environment.mSoundManager->playSound(openSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTeleportPlayer (ref->ref.destCell, ref->ref.doorDest));
}
@ -91,6 +107,9 @@ namespace MWClass
{
// animated door
// TODO return action for rotating the door
// This is a little pointless, but helps with testing
environment.mSoundManager->playSound(openSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
}

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -57,12 +55,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Ingredient::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.ingreds);
}
std::string Ingredient::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Ingredient, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -14,8 +14,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -26,18 +24,18 @@ namespace MWClass
assert (ref->base != NULL);
const std::string &model = ref->base->model;
MWRender::Objects& objects = renderingInterface.getObjects();
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
if (!model.empty())
{
MWRender::Objects& objects = renderingInterface.getObjects();
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
objects.insertMesh(ptr, "meshes\\" + model);
const int color = ref->base->data.color;
const float r = ((color >> 0) & 0xFF) / 255.0f;
const float g = ((color >> 8) & 0xFF) / 255.0f;
const float b = ((color >> 16) & 0xFF) / 255.0f;
const float radius = float (ref->base->data.radius);
objects.insertLight (ptr, r, g, b, radius);
}
const int color = ref->base->data.color;
const float r = ((color >> 0) & 0xFF) / 255.0f;
const float g = ((color >> 8) & 0xFF) / 255.0f;
const float b = ((color >> 16) & 0xFF) / 255.0f;
const float radius = float (ref->base->data.radius);
objects.insertLight (ptr, r, g, b, radius);
}
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
@ -45,13 +43,12 @@ namespace MWClass
ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =
ptr.get<ESM::Light>();
const std::string &model = ref->base->model;
assert (ref->base != NULL);
const std::string &model = ref->base->model;
if(!model.empty()){
physics.insertObjectPhysics(ptr, "meshes\\" + model);
}
}
void Light::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const
@ -89,12 +86,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Light::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.lights);
}
std::string Light::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =

@ -27,10 +27,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -60,12 +58,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Lockpick::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.lockpicks);
}
std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Tool, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -59,12 +57,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Miscellaneous::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.miscItems);
}
std::string Miscellaneous::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -29,7 +29,7 @@ namespace
MWMechanics::NpcStats mNpcStats;
MWMechanics::CreatureStats mCreatureStats;
MWMechanics::Movement mMovement;
MWWorld::ContainerStore<MWWorld::RefData> mContainerStore;
MWWorld::ContainerStore mContainerStore;
virtual MWWorld::CustomData *clone() const;
};
@ -156,7 +156,7 @@ namespace MWClass
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
}
MWWorld::ContainerStore<MWWorld::RefData>& Npc::getContainerStore (const MWWorld::Ptr& ptr)
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
const
{
ensureCustomData (ptr);

@ -35,8 +35,7 @@ namespace MWClass
virtual MWMechanics::NpcStats& getNpcStats (const MWWorld::Ptr& ptr) const;
///< Return NPC stats
virtual MWWorld::ContainerStore<MWWorld::RefData>& getContainerStore (
const MWWorld::Ptr& ptr) const;
virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const;
///< Return container store
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -59,12 +57,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Potion::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.potions);
}
std::string Potion::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Potion, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -8,7 +8,6 @@
#include "../mwworld/ptr.hpp"
#include "../mwworld/actiontake.hpp"
#include "containerutil.hpp"
#include "../mwrender/objects.hpp"
namespace MWClass
@ -58,12 +57,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Probe::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.probes);
}
std::string Probe::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Probe, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -59,12 +57,6 @@ namespace MWClass
new MWWorld::ActionTake (ptr));
}
void Repair::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.repairs);
}
std::string Repair::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Repair, MWWorld::RefData> *ref =

@ -22,10 +22,6 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -20,7 +20,7 @@ namespace MWClass
if (!model.empty())
{
MWRender::Objects& objects = renderingInterface.getObjects();
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), true);
objects.insertMesh(ptr, "meshes\\" + model);
}
}
@ -30,13 +30,12 @@ namespace MWClass
ESMS::LiveCellRef<ESM::Static, MWWorld::RefData> *ref =
ptr.get<ESM::Static>();
const std::string &model = ref->base->model;
assert (ref->base != NULL);
const std::string &model = ref->base->model;
if(!model.empty()){
physics.insertObjectPhysics(ptr, "meshes\\" + model);
}
}
std::string Static::getName (const MWWorld::Ptr& ptr) const

@ -10,8 +10,6 @@
#include "../mwrender/objects.hpp"
#include "containerutil.hpp"
namespace MWClass
{
void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -72,12 +70,6 @@ namespace MWClass
return ref->base->data.health;
}
void Weapon::insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
{
insertIntoContainerStore (ptr, containerStore.weapons);
}
std::string Weapon::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =

@ -28,10 +28,6 @@ namespace MWClass
virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const;
///< Return item max health or throw an exception, if class does not have item health
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
///< Insert into a containe
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -32,8 +32,8 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize)
mBook.pages.pop_back();
}
std::string::iterator wordBegin = text.begin();
std::string::iterator wordEnd;
//std::string::iterator wordBegin = text.begin();
//std::string::iterator wordEnd;
std::string cText = text;

@ -83,27 +83,14 @@ namespace MWInput
MWGui::WindowManager &windows;
OMW::Engine& mEngine;
// Count screenshots.
int shotCount;
/* InputImpl Methods */
// Write screenshot to file.
void screenshot()
{
// Find the first unused filename with a do-while
char buf[50];
do
{
snprintf(buf, 50, "screenshot%03d.png", shotCount++);
} while (boost::filesystem::exists(buf));
ogre.screenshot(buf);
mEngine.screenshot();
}
/* toggleInventory() is called when the user presses the button to toggle the inventory screen. */
void toggleInventory()
{
@ -183,8 +170,7 @@ namespace MWInput
poller(input),
player(_player),
windows(_windows),
mEngine (engine),
shotCount(0)
mEngine (engine)
{
using namespace OEngine::Input;
using namespace OEngine::Render;

@ -99,14 +99,15 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store){
mRend.getScene()->destroySceneNode(base);
base = 0;
}
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++)
{
if(iter->first.getCell() == store){
delete iter->second;
mAllActors.erase(iter);
}
}
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); )
{
if(iter->first.getCell() == store){
delete iter->second;
mAllActors.erase(iter++);
}
else
++iter;
}
}
void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){

@ -101,7 +101,6 @@ namespace MWRender{
}
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){
bool useHandles = skel == creaturemodel->getSkeleton();
shapeNumber = 0;
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
@ -112,6 +111,9 @@ namespace MWRender{
Nif::NiTriShapeCopy& copy = *allshapesiter;
std::vector<Ogre::Vector3>* allvertices = &copy.vertices;
std::vector<Ogre::Vector3>* allnormals = &copy.normals;
//std::set<unsigned int> vertices;
//std::set<unsigned int> normals;
@ -121,8 +123,7 @@ namespace MWRender{
//std::cout << "Name " << copy.sname << "\n";
Ogre::HardwareVertexBufferSharedPtr vbuf = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(0);
Ogre::Real* pReal = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
//Ogre::HardwareVertexBufferSharedPtr vbufNormal = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(1);
// Ogre::Real* pRealNormal = static_cast<Ogre::Real*>(vbufNormal->lock(Ogre::HardwareBuffer::HBL_NORMAL));
std::vector<Ogre::Vector3> initialVertices = copy.morph.getInitialVertices();
//Each shape has multiple indices
@ -181,146 +182,76 @@ namespace MWRender{
std::vector<Nif::NiSkinData::IndividualWeight> inds = iter->second;
int verIndex = iter->first;
Ogre::Vector3 currentVertex = (*allvertices)[verIndex];
Ogre::Vector3 currentNormal = (*allnormals)[verIndex];
Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]);
Ogre::Bone *bonePtr = 0;
if(useHandles)
{
bonePtr = skel->getBone(boneinfocopy->bonehandle);
}
else
bonePtr = skel->getBone(boneinfocopy->bonename);
Ogre::Vector3 vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
Ogre::Quaternion vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
/*if(vecPosRot.find(boneinfocopy->bonehandle) == vecPosRot.end()){
Ogre::Vector3 vecPos;
Ogre::Quaternion vecRot;
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot>::iterator result = vecRotPos.find(boneinfocopy);
if(result == vecRotPos.end()){
bonePtr = skel->getBone(boneinfocopy->bonename);
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
if(useHandles){
PosAndRot both;
both.vecPos = vecPos;
both.vecRot = vecRot;
vecPosRot[boneinfocopy->bonehandle] = both;
}
vecRotPos[boneinfocopy] = both;
}
else{
PosAndRot both = vecPosRot[boneinfocopy->bonehandle];
PosAndRot both = result->second;
vecPos = both.vecPos;
vecRot = both.vecRot;
}*/
}
Ogre::Vector3 absVertPos = (vecPos + vecRot * currentVertex) * inds[0].weight;
for(std::size_t i = 1; i < inds.size(); i++){
boneinfocopy = &(allshapesiter->boneinfo[inds[i].boneinfocopyindex]);
if(useHandles)
bonePtr = skel->getBone(boneinfocopy->bonehandle);
else
bonePtr = skel->getBone(boneinfocopy->bonename);
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
result = vecRotPos.find(boneinfocopy);
/*if(vecPosRot.find(boneinfocopy->bonehandle) == vecPosRot.end()){
if(result == vecRotPos.end()){
bonePtr = skel->getBone(boneinfocopy->bonename);
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
if(useHandles){
PosAndRot both;
both.vecPos = vecPos;
both.vecRot = vecRot;
vecPosRot[boneinfocopy->bonehandle] = both;
}
vecRotPos[boneinfocopy] = both;
}
else{
PosAndRot both = vecPosRot[boneinfocopy->bonehandle];
PosAndRot both = result->second;
vecPos = both.vecPos;
vecRot = both.vecRot;
}*/
}
absVertPos += (vecPos + vecRot * currentVertex) * inds[i].weight;
}
Ogre::Real* addr = (pReal + 3 * verIndex);
*addr = absVertPos.x;
*(addr+1) = absVertPos.y;
*(addr+2) = absVertPos.z;
}
#if 0
for (unsigned int i = 0; i < boneinfovector.size(); i++)
{
Nif::NiSkinData::BoneInfoCopy boneinfo = boneinfovector[i];
if(skel->hasBone(boneinfo.bonename)){
Ogre::Bone *bonePtr = skel->getBone(boneinfo.bonename);
Ogre::Vector3 vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfo.trafo.trans;
Ogre::Quaternion vecRot = bonePtr->_getDerivedOrientation() * boneinfo.trafo.rotation;
for (unsigned int j=0; j < boneinfo.weights.size(); j++)
{
unsigned int verIndex = boneinfo.weights[j].vertex;
if(vertices.find(verIndex) == vertices.end())
{
Ogre::Vector3 absVertPos = vecPos + vecRot * allvertices[verIndex];
absVertPos = absVertPos * boneinfo.weights[j].weight;
vertices.insert(verIndex);
Ogre::Real* addr = (pReal + 3 * verIndex);
*addr = absVertPos.x;
*(addr+1) = absVertPos.y;
*(addr+2) = absVertPos.z;
}
else
{
Ogre::Vector3 absVertPos = vecPos + vecRot * allvertices[verIndex];
absVertPos = absVertPos * boneinfo.weights[j].weight;
Ogre::Vector3 old = Ogre::Vector3(pReal + 3 * verIndex);
absVertPos = absVertPos + old;
Ogre::Real* addr = (pReal + 3 * verIndex);
*addr = absVertPos.x;
*(addr+1) = absVertPos.y;
*(addr+2) = absVertPos.z;
//std::cout << "Vertex" << verIndex << "Weight: " << boneinfo.weights[i].weight << "was seen twice\n";
}
if(normals.find(verIndex) == normals.end())
{
Ogre::Vector3 absNormalsPos = vecRot * allnormals[verIndex];
absNormalsPos = absNormalsPos * boneinfo.weights[j].weight;
normals.insert(verIndex);
Ogre::Real* addr = (pRealNormal + 3 * verIndex);
*addr = absNormalsPos.x;
*(addr+1) = absNormalsPos.y;
*(addr+2) = absNormalsPos.z;
}
else
{
Ogre::Vector3 absNormalsPos = vecRot * allnormals[verIndex];
absNormalsPos = absNormalsPos * boneinfo.weights[j].weight;
Ogre::Vector3 old = Ogre::Vector3(pRealNormal + 3 * verIndex);
absNormalsPos = absNormalsPos + old;
Ogre::Real* addr = (pRealNormal + 3 * verIndex);
*addr = absNormalsPos.x;
*(addr+1) = absNormalsPos.y;
*(addr+2) = absNormalsPos.z;
}
#endif
//}
//}
//} //Comment out
;
}
else
{
@ -329,11 +260,13 @@ namespace MWRender{
Ogre::Vector3 shapetrans = copy.trafo.trans;
float shapescale = copy.trafo.scale;
std::vector<std::string> boneSequence = copy.boneSequence;
std::vector<std::string>::iterator boneSequenceIter = boneSequence.begin();
Ogre::Vector3 transmult;
Ogre::Quaternion rotmult;
float scale;
if(skel->hasBone(*boneSequenceIter)){
if(boneSequence.size() > 0){
std::vector<std::string>::iterator boneSequenceIter = boneSequence.begin();
if(skel->hasBone(*boneSequenceIter)){
Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter);
@ -360,6 +293,7 @@ namespace MWRender{
//std::cout << "Position: " << transmult << "Rotation: " << rotmult << "\n";
}
}
else
{
transmult = shapetrans;
@ -392,7 +326,7 @@ namespace MWRender{
}
vbuf->unlock();
//vbufNormal->unlock();
}
}
@ -465,22 +399,18 @@ namespace MWRender{
base->getAllAnimationStates()->_notifyDirty();
//base->_updateAnimation();
base->_notifyMoved();
//base->_notifyMoved();
for(unsigned int i = 0; i < entityparts.size(); i++){
Ogre::SkeletonInstance* skel = entityparts[i]->getSkeleton();
for(unsigned int i = 0; i < entityparts.size(); i++){
//Ogre::SkeletonInstance* skel = entityparts[i]->getSkeleton();
Ogre::Bone* b = skel->getRootBone();
b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3));//This is a trick
skel->_updateTransforms();
// skel->_notifyManualBonesDirty();
entityparts[i]->getAllAnimationStates()->_notifyDirty();
//entityparts[i]->_updateAnimation();
entityparts[i]->_notifyMoved();
}
std::vector<Nif::NiKeyframeData>::iterator iter;
int slot = 0;
if(transformations){
@ -488,9 +418,7 @@ namespace MWRender{
if(time < iter->getStartTime() || time < startTime || time > iter->getStopTime())
{
slot++;
//iter++;
continue;
}
float x;
@ -511,7 +439,6 @@ namespace MWRender{
timeIndex(time, ttime, tindexI[slot], tindexJ, x);
//std::cout << "X: " << x << " X2: " << x2 << "\n";
Ogre::Vector3 t;
Ogre::Quaternion r;
@ -526,7 +453,6 @@ namespace MWRender{
bool bQuats = quats.size() > 0;
if(bQuats){
r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true);
//bone->setOrientation(r);
}
skel = base->getSkeleton();
if(skel->hasBone(iter->getBonename())){
@ -539,27 +465,10 @@ namespace MWRender{
skel->_updateTransforms();
//skel->_notifyManualBonesDirty();
base->getAllAnimationStates()->_notifyDirty();
//base->_updateAnimation();
base->_notifyMoved();
}
for(std::size_t i = 0; i < entityparts.size(); i++){
skel = entityparts[i]->getSkeleton();
if(skel->hasBone(iter->getBonename())){
Ogre::Bone* bone = skel->getBone(iter->getBonename());
if(bTrans)
bone->setPosition(t);
if(bQuats)
bone->setOrientation(r);
skel->_updateTransforms();
//skel->_notifyManualBonesDirty();
entityparts[i]->getAllAnimationStates()->_notifyDirty();
// entityparts[i]->_updateAnimation();
entityparts[i]->_notifyMoved();
}
}
slot++;
}
}

@ -26,6 +26,7 @@ class Animation{
Ogre::SceneNode* insert;
OEngine::Render::OgreRenderer &mRend;
MWWorld::Environment& mEnvironment;
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot> vecRotPos;
static std::map<std::string, int> mUniqueIDs;

@ -38,6 +38,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environme
}
void CreatureAnimation::runAnimation(float timepassed){
vecRotPos.clear();
if(animate > 0){
//Add the amount of time passed to time

@ -43,6 +43,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2);
bool female = tolower(secondtolast) == 'f';
bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_";
/*std::cout << "Race: " << ref->base->race ;
if(female){
std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n";
@ -67,6 +68,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
//stay in the same place when we skipanim, or open a gui window
if((transformations = (NIFLoader::getSingletonPtr())->getAnim(smodel))){
for(unsigned int init = 0; init < transformations->size(); init++){
@ -177,7 +179,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
if(clavicler)
insertBoundedPart("meshes\\" + clavicler->model , "Right Clavicle", base);*/
if(neck)
{
insertBoundedPart("meshes\\" + neck->model, "Neck");
@ -213,6 +214,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
}
Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){
NIFLoader::load(mesh);
Entity* ent = mRend.getScene()->createEntity(mesh);
@ -225,15 +227,7 @@ void NpcAnimation::insertFreePart(const std::string &mesh, const std::string suf
Ogre::Entity* ent = mRend.getScene()->createEntity(meshNumbered);
/*MaterialPtr material = ent->getSubEntity(0)->getMaterial();
material->removeAllTechniques();
Ogre::Technique* tech = material->createTechnique();
Pass* pass2 = tech->createPass();
pass2->setVertexProgram("Ogre/HardwareSkinningTwoWeights");
pass2->setColourWriteEnabled(false);
//tech->setSchemeName("blahblah");*/
insert->attachObject(ent);
@ -249,6 +243,7 @@ void NpcAnimation::insertFreePart(const std::string &mesh, const std::string suf
void NpcAnimation::runAnimation(float timepassed){
//1. Add the amount of time passed to time
//2. Handle the animation transforms dependent on time
@ -267,22 +262,17 @@ void NpcAnimation::runAnimation(float timepassed){
}
handleAnimationTransforms();
Ogre::Vector3 current = insert->_getWorldAABB().getCenter();
std::vector<std::vector<Nif::NiTriShapeCopy>*>::iterator shapepartsiter = shapeparts.begin();
std::vector<Ogre::Entity*>::iterator entitypartsiter = entityparts.begin();
while(shapepartsiter != shapeparts.end())
{
vecRotPos.clear();
std::vector<Nif::NiTriShapeCopy>* shapes = *shapepartsiter;
Ogre::Entity* theentity = *entitypartsiter;
/*
Pass* pass = theentity->getSubEntity(0)->getMaterial()->getBestTechnique()->getPass(0);
if (pass->hasVertexProgram() && pass->getVertexProgram()->isSkeletalAnimationIncluded())
std::cout << "It's hardware\n";
else
std::cout << "It's software\n";*/
handleShapes(shapes, theentity, theentity->getSkeleton());
handleShapes(shapes, theentity, base->getSkeleton());
shapepartsiter++;
entitypartsiter++;
}

@ -1,11 +1,11 @@
#include "objects.hpp"
#include <OgreSceneNode.h>
#include <components/nifogre/ogre_nif_loader.hpp>
using namespace Ogre;
using namespace MWRender;
bool Objects::lightConst = false;
float Objects::lightConstValue = 0.0f;
@ -23,10 +23,24 @@ bool Objects::lightOutQuadInLin = false;
int Objects::uniqueID = 0;
void Objects::setMwRoot(Ogre::SceneNode* root){
void Objects::clearSceneNode (Ogre::SceneNode *node)
{
/// \todo This should probably be moved into OpenEngine at some point.
for (int i=node->numAttachedObjects()-1; i>=0; --i)
{
Ogre::MovableObject *object = node->getAttachedObject (i);
node->detachObject (object);
mRenderer.getScene()->destroyMovableObject (object);
}
}
void Objects::setMwRoot(Ogre::SceneNode* root)
{
mMwRoot = root;
}
void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){
void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
{
Ogre::SceneNode* root = mMwRoot;
Ogre::SceneNode* cellnode;
if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end())
@ -49,90 +63,98 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){
f = ptr.getCellRef().pos.rot;
// Rotate around X axis
Quaternion xr(Radian(-f[0]), Vector3::UNIT_X);
Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X);
// Rotate around Y axis
Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y);
Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y);
// Rotate around Z axis
Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z);
Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z);
// Rotates first around z, then y, then x
// Rotates first around z, then y, then x
insert->setOrientation(xr*yr*zr);
if (!enabled)
insert->setVisible (false);
ptr.getRefData().setBaseNode(insert);
isStatic = static_;
mIsStatic = static_;
}
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh){
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
{
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
assert(insert);
NifOgre::NIFLoader::load(mesh);
Entity *ent = mRend.getScene()->createEntity(mesh);
Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh);
if(!isStatic)
if(!mIsStatic)
{
insert->attachObject(ent);
}
else
{
Ogre::StaticGeometry* sg = 0;
if(mSG.find(ptr.getCell()) == mSG.end())
if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
{
uniqueID = uniqueID +1;
sg = mRend.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
//Create the scenenode and put it in the map
mSG[ptr.getCell()] = sg;
mStaticGeometry[ptr.getCell()] = sg;
// This specifies the size of a single batch region.
// If it is set too high:
// - there will be problems choosing the correct lights
// - the culling will be more inefficient
// If it is set too low:
// - there will be too many batches.
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
}
else
{
sg = mSG[ptr.getCell()];
sg = mStaticGeometry[ptr.getCell()];
}
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
sg->setRegionDimensions(Ogre::Vector3(100000,10000,100000));
mRend.getScene()->destroyEntity(ent);
mRenderer.getScene()->destroyEntity(ent);
}
}
void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius){
Ogre::SceneNode* insert = mRend.getScene()->getSceneNode(ptr.getRefData().getHandle());
void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius)
{
Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle());
assert(insert);
Ogre::Light *light = mRend.getScene()->createLight();
Ogre::Light *light = mRenderer.getScene()->createLight();
light->setDiffuseColour (r, g, b);
float cval=0.0f, lval=0.0f, qval=0.0f;
if(lightConst)
cval = lightConstValue;
if(!lightOutQuadInLin)
{
if(lightLinear)
radius *= lightLinearRadiusMult;
if(lightQuadratic)
radius *= lightQuadraticRadiusMult;
if(lightLinear)
lval = lightLinearValue / pow(radius, lightLinearMethod);
if(lightQuadratic)
qval = lightQuadraticValue / pow(radius, lightQuadraticMethod);
}
else
{
// FIXME:
// Do quadratic or linear, depending if we're in an exterior or interior
// cell, respectively. Ignore lightLinear and lightQuadratic.
}
light->setAttenuation(10*radius, cval, lval, qval);
insert->attachObject(light);
if(!lightOutQuadInLin)
{
if(lightLinear)
radius *= lightLinearRadiusMult;
if(lightQuadratic)
radius *= lightQuadraticRadiusMult;
if(lightLinear)
lval = lightLinearValue / pow(radius, lightLinearMethod);
if(lightQuadratic)
qval = lightQuadraticValue / pow(radius, lightQuadraticMethod);
}
else
{
// FIXME:
// Do quadratic or linear, depending if we're in an exterior or interior
// cell, respectively. Ignore lightLinear and lightQuadratic.
}
light->setAttenuation(10*radius, cval, lval, qval);
insert->attachObject(light);
}
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
@ -145,8 +167,9 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr)
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
if (iter->second==parent)
{
clearSceneNode (base);
base->removeAndDestroyAllChildren();
mRend.getScene()->destroySceneNode (base);
mRenderer.getScene()->destroySceneNode (base);
ptr.getRefData().setBaseNode (0);
return true;
}
@ -157,29 +180,35 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr)
return true;
}
void Objects::removeCell(MWWorld::Ptr::CellStore* store){
void Objects::removeCell(MWWorld::Ptr::CellStore* store)
{
if(mCellSceneNodes.find(store) != mCellSceneNodes.end())
{
Ogre::SceneNode* base = mCellSceneNodes[store];
for (int i=0; i<base->numChildren(); ++i)
clearSceneNode (static_cast<Ogre::SceneNode *> (base->getChild (i)));
base->removeAndDestroyAllChildren();
mCellSceneNodes.erase(store);
mRend.getScene()->destroySceneNode(base);
mRenderer.getScene()->destroySceneNode(base);
base = 0;
}
if(mSG.find(store) != mSG.end())
if(mStaticGeometry.find(store) != mStaticGeometry.end())
{
Ogre::StaticGeometry* sg = mSG[store];
mSG.erase(store);
mRend.getScene()->destroyStaticGeometry (sg);
Ogre::StaticGeometry* sg = mStaticGeometry[store];
mStaticGeometry.erase(store);
mRenderer.getScene()->destroyStaticGeometry (sg);
sg = 0;
}
}
void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell){
if(mSG.find(&cell) != mSG.end())
void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
{
if(mStaticGeometry.find(&cell) != mStaticGeometry.end())
{
Ogre::StaticGeometry* sg = mSG[&cell];
Ogre::StaticGeometry* sg = mStaticGeometry[&cell];
sg->build();
}
}

@ -1,20 +1,21 @@
#ifndef _GAME_RENDER_OBJECTS_H
#define _GAME_RENDER_OBJECTS_H
#include "components/esm_store/cell_store.hpp"
#include <openengine/ogre/renderer.hpp>
#include <components/esm_store/cell_store.hpp>
#include "../mwworld/refdata.hpp"
#include "../mwworld/ptr.hpp"
#include <openengine/ogre/renderer.hpp>
namespace MWRender{
class Objects{
OEngine::Render::OgreRenderer &mRend;
OEngine::Render::OgreRenderer &mRenderer;
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mSG;
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
Ogre::SceneNode* mMwRoot;
bool isStatic;
bool mIsStatic;
static int uniqueID;
static bool lightConst;
static float lightConstValue;
@ -30,8 +31,12 @@ class Objects{
static float lightQuadraticRadiusMult;
static bool lightOutQuadInLin;
void clearSceneNode (Ogre::SceneNode *node);
///< Remove all movable objects from \a node.
public:
Objects(OEngine::Render::OgreRenderer& _rend): mRend(_rend){}
Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer){}
~Objects(){}
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);

@ -20,10 +20,9 @@ using namespace Ogre;
namespace MWRender {
RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment)
:mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mDebugging(engine)
:mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mDebugging(engine)
{
mRendering.createScene("PlayerCam", 55, 5);
mSkyManager = MWRender::SkyManager::create(mRendering.getWindow(), mRendering.getCamera(), resDir);
// Set default mipmap level (NB some APIs ignore this)
TextureManager::getSingleton().setDefaultNumMipmaps(5);
@ -51,6 +50,9 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode();
cameraPitchNode->attachObject(mRendering.getCamera());
//mSkyManager = 0;
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera());
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
mSun = 0;
}
@ -62,6 +64,10 @@ RenderingManager::~RenderingManager ()
delete mSkyManager;
}
MWRender::SkyManager* RenderingManager::getSkyManager()
{
return mSkyManager;
}
MWRender::Objects& RenderingManager::getObjects(){
return mObjects;
@ -74,6 +80,11 @@ MWRender::Player& RenderingManager::getPlayer(){
return (*mPlayer);
}
OEngine::Render::Fader* RenderingManager::getFader()
{
return mRendering.getFader();
}
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store){
mObjects.removeCell(store);
mActors.removeCell(store);
@ -122,31 +133,40 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve
void RenderingManager::update (float duration){
mActors.update (duration);
mSkyManager->update(duration);
mRendering.update(duration);
}
void RenderingManager::skyEnable ()
{
if(mSkyManager)
mSkyManager->enable();
}
void RenderingManager::skyDisable ()
{
mSkyManager->disable();
if(mSkyManager)
mSkyManager->disable();
}
void RenderingManager::skySetHour (double hour)
{
mSkyManager->setHour(hour);
if(mSkyManager)
mSkyManager->setHour(hour);
}
void RenderingManager::skySetDate (int day, int month)
{
mSkyManager->setDate(day, month);
if(mSkyManager)
mSkyManager->setDate(day, month);
}
int RenderingManager::skyGetMasserPhase() const
{
return mSkyManager->getMasserPhase();
}
@ -155,12 +175,28 @@ int RenderingManager::skyGetSecundaPhase() const
return mSkyManager->getSecundaPhase();
}
void RenderingManager::skySetMoonColour (bool red)
{
mSkyManager->setMoonColour(red);
void RenderingManager::skySetMoonColour (bool red){
if(mSkyManager)
mSkyManager->setMoonColour(red);
}
bool RenderingManager::toggleRenderMode(int mode){
return mDebugging.toggleRenderMode(mode);
bool RenderingManager::toggleRenderMode(int mode)
{
if (mode == MWWorld::World::Render_CollisionDebug)
return mDebugging.toggleRenderMode(mode);
else // if (mode == MWWorld::World::Render_Wireframe)
{
if (mRendering.getCamera()->getPolygonMode() == PM_SOLID)
{
mRendering.getCamera()->setPolygonMode(PM_WIREFRAME);
return true;
}
else
{
mRendering.getCamera()->setPolygonMode(PM_SOLID);
return false;
}
}
}
void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
@ -168,14 +204,22 @@ void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
Ogre::ColourValue color;
color.setAsABGR (mCell.cell->ambi.fog);
float high = 4500 + 9000 * (1-mCell.cell->ambi.fogDensity);
float low = 200;
configureFog(mCell.cell->ambi.fogDensity, color);
}
mRendering.getScene()->setFog (FOG_LINEAR, color, 0, low, high);
mRendering.getCamera()->setFarClipDistance (high + 10);
mRendering.getViewport()->setBackgroundColour (color);
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
{
/// \todo make the viewing distance and fog start/end configurable
float low = 3000 / density;
float high = 6200 / density;
mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high);
mRendering.getCamera()->setFarClipDistance ( high );
mRendering.getViewport()->setBackgroundColour (colour);
}
void RenderingManager::setAmbientMode()
{
switch (mAmbientMode)
@ -244,4 +288,38 @@ void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr)
mActors.skipAnimation(ptr);
}
void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
{
mSun->setDiffuseColour(colour);
}
void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
{
mRendering.getScene()->setAmbientLight(colour);
}
void RenderingManager::sunEnable()
{
if (mSun) mSun->setVisible(true);
}
void RenderingManager::sunDisable()
{
if (mSun) mSun->setVisible(false);
}
void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
{
// direction * -1 (because 'direction' is camera to sun vector and not sun to camera),
// then convert from MW to ogre coordinates (swap y,z and make y negative)
if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y));
mSkyManager->setSunDirection(direction);
}
void RenderingManager::setGlare(bool glare)
{
mSkyManager->setGlare(glare);
}
} // namespace

@ -9,6 +9,7 @@
#include <utility>
#include <openengine/ogre/renderer.hpp>
#include <openengine/ogre/fader.hpp>
#include <openengine/bullet/physic.hpp>
#include <vector>
@ -61,9 +62,13 @@ class RenderingManager: private RenderingInterface {
/// MWWorld::Player has been rewritten to not need access
/// to internal details of the rendering system anymore
SkyManager* getSkyManager();
void toggleLight();
bool toggleRenderMode(int mode);
OEngine::Render::Fader* getFader();
void removeCell (MWWorld::Ptr::CellStore *store);
/// \todo this function should be removed later. Instead the rendering subsystems should track
@ -82,6 +87,13 @@ class RenderingManager: private RenderingInterface {
void update (float duration);
void setAmbientColour(const Ogre::ColourValue& colour);
void setSunColour(const Ogre::ColourValue& colour);
void setSunDirection(const Ogre::Vector3& direction);
void sunEnable();
void sunDisable();
void setGlare(bool glare);
void skyEnable ();
void skyDisable ();
void skySetHour (double hour);
@ -90,9 +102,13 @@ class RenderingManager: private RenderingInterface {
int skyGetSecundaPhase() const;
void skySetMoonColour (bool red);
void configureAmbient(ESMS::CellStore<MWWorld::RefData> &mCell);
/// configure fog according to cell
void configureFog(ESMS::CellStore<MWWorld::RefData> &mCell);
/// configure fog manually
void configureFog(const float density, const Ogre::ColourValue& colour);
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
int number = 1);
///< Run animation for a MW-reference. Calls to this function for references that are currently not
@ -108,7 +124,9 @@ class RenderingManager: private RenderingInterface {
private:
void setAmbientMode();
SkyManager* mSkyManager;
OEngine::Render::OgreRenderer &mRendering;
MWRender::Objects mObjects;

@ -1,116 +1,764 @@
#include "sky.hpp"
#include "Caelum.h"
namespace MWRender
{
//
// Implements a Caelum sky with default settings.
//
// Note: this is intended as a temporary solution to provide some form of
// sky rendering. This code will obviously need significant tailoring to
// support fidelity with Morrowind's rendering. Before doing major work
// on this class, more research should be done to determine whether
// Caelum or another plug-in such as SkyX would be best for the long-term.
//
class CaelumManager : public SkyManager
{
protected:
Caelum::CaelumSystem* mpCaelumSystem;
public:
CaelumManager (Ogre::RenderWindow* pRenderWindow,
Ogre::Camera* pCamera,
const boost::filesystem::path& resDir);
virtual ~CaelumManager ();
#include <OgreCamera.h>
#include <OgreRenderWindow.h>
#include <OgreSceneNode.h>
#include <OgreMesh.h>
#include <OgreSceneManager.h>
#include <OgreHardwareVertexBuffer.h>
#include <OgreHighLevelGpuProgramManager.h>
virtual void enable() {}
#include <components/nifogre/ogre_nif_loader.hpp>
virtual void disable() {}
using namespace MWRender;
using namespace Ogre;
virtual void setHour (double hour) {}
///< will be called even when sky is disabled.
// the speed at which the clouds are animated
#define CLOUD_SPEED 0.001
virtual void setDate (int day, int month) {}
///< will be called even when sky is disabled.
// this distance has to be set accordingly so that the
// celestial bodies are behind the clouds, but in front of the atmosphere
#define CELESTIAL_BODY_DISTANCE 1000.f
virtual int getMasserPhase() const { return 0; }
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
/// 3 waxing or waning gibbous, 4 full moon
BillboardObject::BillboardObject( const String& textureName,
const float initialSize,
const Vector3& position,
SceneNode* rootNode)
{
init(textureName, initialSize, position, rootNode);
}
virtual int getSecundaPhase() const { return 0; }
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
/// 3 waxing or waning gibbous, 4 full moon
BillboardObject::BillboardObject()
{
}
virtual void setMoonColour (bool red) {}
};
void BillboardObject::setVisible(const bool visible)
{
mNode->setVisible(visible);
}
CaelumManager::CaelumManager (Ogre::RenderWindow* pRenderWindow,
Ogre::Camera* pCamera,
const boost::filesystem::path& resDir)
: mpCaelumSystem (NULL)
{
using namespace Ogre;
using namespace Caelum;
void BillboardObject::setSize(const float size)
{
mNode->setScale(size, size, size);
}
assert(pCamera);
assert(pRenderWindow);
void BillboardObject::setVisibility(const float visibility)
{
mMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, visibility);
}
// Load the Caelum resources
//
ResourceGroupManager::getSingleton().addResourceLocation((resDir / "caelum").string(), "FileSystem", "Caelum");
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
void BillboardObject::setPosition(const Vector3& pPosition)
{
Vector3 normalised = pPosition.normalisedCopy();
Vector3 finalPosition = normalised * CELESTIAL_BODY_DISTANCE;
// Load the Caelum resources
//
Ogre::SceneManager* pScene = pCamera->getSceneManager();
Caelum::CaelumSystem::CaelumComponent componentMask = CaelumSystem::CAELUM_COMPONENTS_DEFAULT;
mpCaelumSystem = new Caelum::CaelumSystem (Root::getSingletonPtr(), pScene, componentMask);
mBBSet->setCommonDirection( -normalised );
// Set time acceleration.
mpCaelumSystem->getUniversalClock()->setTimeScale(128);
mNode->setPosition(finalPosition);
}
// Disable fog since OpenMW is handling OGRE fog elsewhere
mpCaelumSystem->setManageSceneFog(false);
Vector3 BillboardObject::getPosition() const
{
return mNode->getPosition();
}
void BillboardObject::setColour(const ColourValue& pColour)
{
mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour);
}
void BillboardObject::setRenderQueue(unsigned int id)
{
mBBSet->setRenderQueueGroup(id);
}
SceneNode* BillboardObject::getNode()
{
return mNode;
}
void BillboardObject::init(const String& textureName,
const float initialSize,
const Vector3& position,
SceneNode* rootNode)
{
SceneManager* sceneMgr = rootNode->getCreator();
// Change the camera far distance to make sure the sky is not clipped
pCamera->setFarClipDistance(50000);
Vector3 finalPosition = position.normalisedCopy() * CELESTIAL_BODY_DISTANCE;
// Register Caelum as an OGRE listener
pRenderWindow->addListener(mpCaelumSystem);
Root::getSingletonPtr()->addFrameListener(mpCaelumSystem);
static unsigned int bodyCount=0;
/// \todo These billboards are not 100% correct, might want to revisit them later
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
mBBSet->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+2);
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
mBBSet->setCommonDirection( -position.normalisedCopy() );
mNode = rootNode->createChildSceneNode();
mNode->setPosition(finalPosition);
mNode->attachObject(mBBSet);
mBBSet->createBillboard(0,0,0);
mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
mMaterial->removeAllTechniques();
Pass* p = mMaterial->createTechnique()->createPass();
p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
p->setDepthCheckEnabled(false);
p->setDepthWriteEnabled(false);
p->setSelfIllumination(1.0,1.0,1.0);
p->setDiffuse(0.0,0.0,0.0,1.0);
p->setAmbient(0.0,0.0,0.0);
p->createTextureUnitState(textureName);
mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount));
bodyCount++;
}
Moon::Moon( const String& textureName,
const float initialSize,
const Vector3& position,
SceneNode* rootNode)
{
init(textureName, initialSize, position, rootNode);
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
HighLevelGpuProgramPtr vshader;
if (mgr.resourceExists("Moon_VP"))
vshader = mgr.getByName("Moon_VP");
else
vshader = mgr.createProgram("Moon_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM);
vshader->setParameter("profiles", "vs_2_x arbvp1");
vshader->setParameter("entry_point", "main_vp");
StringUtil::StrStreamType outStream;
outStream <<
"void main_vp( \n"
" float4 position : POSITION, \n"
" in float2 uv : TEXCOORD0, \n"
" out float2 oUV : TEXCOORD0, \n"
" out float4 oPosition : POSITION, \n"
" uniform float4x4 worldViewProj \n"
") \n"
"{ \n"
" oUV = uv; \n"
" oPosition = mul( worldViewProj, position ); \n"
"}";
vshader->setSource(outStream.str());
vshader->load();
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
mMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
HighLevelGpuProgramPtr fshader;
if (mgr.resourceExists("Moon_FP"))
fshader = mgr.getByName("Moon_FP");
else
fshader = mgr.createProgram("Moon_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_FRAGMENT_PROGRAM);
fshader->setParameter("profiles", "ps_2_x arbfp1");
fshader->setParameter("entry_point", "main_fp");
StringUtil::StrStreamType outStream2;
outStream2 <<
"void main_fp( \n"
" in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n"
" uniform sampler2D texture : TEXUNIT0, \n"
" uniform float4 diffuse, \n"
" uniform float4 emissive \n"
") \n"
"{ \n"
" float4 tex = tex2D(texture, uv); \n"
" oColor = float4(emissive.xyz,1) * tex2D(texture, uv) * float4(1,1,1,diffuse.a); \n"
" float bump = pow((1-diffuse.a),4); \n"
" oColor.rgb += float3(bump, bump, bump)*0.5; \n"
"}";
fshader->setSource(outStream2.str());
fshader->load();
fshader->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
mMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName());
setVisibility(1.0);
mPhase = Moon::Phase_Full;
}
void Moon::setType(const Moon::Type& type)
{
mType = type;
}
/// \todo the moon phase rendering is not correct - the dark part of the moon does not occlude the stars
void Moon::setPhase(const Moon::Phase& phase)
{
Ogre::String textureName = "textures\\tx_";
if (mType == Moon::Type_Secunda) textureName += "secunda_";
else textureName += "masser_";
if (phase == Moon::Phase_New) textureName += "new";
else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax";
else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax";
else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax";
else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan";
else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan";
else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan";
else if (phase == Moon::Phase_Full) textureName += "full";
textureName += ".dds";
mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(textureName);
mPhase = phase;
}
Moon::Phase Moon::getPhase() const
{
return mPhase;
}
unsigned int Moon::getPhaseInt() const
{
if (mPhase == Moon::Phase_New) return 0;
else if (mPhase == Moon::Phase_WaxingCrescent) return 1;
else if (mPhase == Moon::Phase_WaningCrescent) return 1;
else if (mPhase == Moon::Phase_WaxingHalf) return 2;
else if (mPhase == Moon::Phase_WaningHalf) return 2;
else if (mPhase == Moon::Phase_WaxingGibbous) return 3;
else if (mPhase == Moon::Phase_WaningGibbous) return 3;
else if (mPhase == Moon::Phase_Full) return 4;
return 0;
}
void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType)
{
// Get the vertex colour buffer of this mesh
const Ogre::VertexElement* ves_diffuse = ent->getMesh()->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE );
HardwareVertexBufferSharedPtr colourBuffer = ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource());
// Lock
void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL);
// Iterate over all vertices
int vertex_size = colourBuffer->getVertexSize();
float * currentVertex = NULL;
for (unsigned int i=0; i<colourBuffer->getNumVertices(); ++i)
{
// Get a pointer to the vertex colour
ves_diffuse->baseVertexPointerToElement( pData, &currentVertex );
unsigned char alpha;
if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row
else if (meshType == 1)
{
if (i>= 49 && i <= 64) alpha = 0; // bottom-most row
else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row
else alpha = 255;
}
uint8 tmpR = static_cast<uint8>(255);
uint8 tmpG = static_cast<uint8>(255);
uint8 tmpB = static_cast<uint8>(255);
uint8 tmpA = static_cast<uint8>(alpha);
// This does not matter since R and B are always 1.
/*VertexElementType format = Root::getSingleton().getRenderSystem()->getColourVertexElementType();
switch (format)
{
case VET_COLOUR_ARGB:
std::swap(tmpR, tmpB);
break;
case VET_COLOUR_ABGR:
break;
default:
break;
}*/
// Modify
*((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24);
// Move to the next vertex
pData = static_cast<unsigned char *> (pData) + vertex_size;
}
CaelumManager::~CaelumManager()
// Unlock
ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock();
}
SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) :
mGlareFade(0), mGlareEnabled(false)
{
mViewport = pCamera->getViewport();
mSceneMgr = pMwRoot->getCreator();
mRootNode = pCamera->getParentSceneNode()->createChildSceneNode();
mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates
mRootNode->setInheritOrientation(false);
/// \todo preload all the textures and meshes that are used for sky rendering
// Create overlay used for thunderstorm
MaterialPtr material = MaterialManager::getSingleton().create( "ThunderMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
Pass* pass = material->getTechnique(0)->getPass(0);
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
mThunderTextureUnit = pass->createTextureUnitState();
mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f)); // always black colour
mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.5f);
OverlayManager& ovm = OverlayManager::getSingleton();
mThunderOverlay = ovm.create( "ThunderOverlay" );
OverlayContainer* overlay_panel;
overlay_panel = (OverlayContainer*)ovm.createOverlayElement("Panel", "ThunderPanel");
overlay_panel->_setPosition(0, 0);
overlay_panel->_setDimensions(1, 1);
overlay_panel->setMaterialName( "ThunderMaterial" );
overlay_panel->show();
mThunderOverlay->add2D(overlay_panel);
mThunderOverlay->hide();
mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode);
mSecunda->setType(Moon::Type_Secunda);
mSecunda->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+4);
mMasser = new Moon("textures\\tx_masser_full.dds", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode);
mMasser->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+3);
mMasser->setType(Moon::Type_Masser);
mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode);
mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode);
mSunGlare->setRenderQueue(RENDER_QUEUE_SKIES_LATE);
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
// Stars
/// \todo sky_night_02.nif (available in Bloodmoon)
MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif");
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
night1_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+1);
mAtmosphereNight = mRootNode->createChildSceneNode();
mAtmosphereNight->attachObject(night1_ent);
for (unsigned int i=0; i<night1_ent->getNumSubEntities(); ++i)
{
if (mpCaelumSystem)
mpCaelumSystem->shutdown (false);
MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial();
mp->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
mp->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0);
mp->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 1.0);
mp->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
mp->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
mStarsMaterials[i] = mp;
}
/// Creates and connects the sky rendering component to OGRE.
///
/// \return NULL on failure.
///
SkyManager* SkyManager::create (Ogre::RenderWindow* pRenderWindow,
Ogre::Camera* pCamera,
const boost::filesystem::path& resDir)
// Stars vertex shader
HighLevelGpuProgramPtr vshader3 = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_VERTEX_PROGRAM);
vshader3->setParameter("profiles", "vs_2_x arbvp1");
vshader3->setParameter("entry_point", "main_vp");
StringUtil::StrStreamType outStream4;
outStream4 <<
"void main_vp( \n"
" float4 position : POSITION, \n"
" in float2 uv : TEXCOORD0, \n"
" out float2 oUV : TEXCOORD0, \n"
" out float oFade : TEXCOORD1, \n"
" out float4 oPosition : POSITION, \n"
" uniform float4x4 worldViewProj \n"
") \n"
"{ \n"
" oUV = uv; \n"
" oFade = (position.z > 50) ? 1.f : 0.f; \n"
" oPosition = mul( worldViewProj, position ); \n"
"}";
vshader3->setSource(outStream4.str());
vshader3->load();
vshader3->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
night1_ent->getSubEntity(3)->getMaterial()->getTechnique(0)->getPass(0)->setVertexProgram(vshader3->getName());
// Stars fragment shader
HighLevelGpuProgramPtr stars_fp = mgr.createProgram("Stars_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_FRAGMENT_PROGRAM);
stars_fp->setParameter("profiles", "ps_2_x arbfp1");
stars_fp->setParameter("entry_point", "main_fp");
StringUtil::StrStreamType outStream5;
outStream5 <<
"void main_fp( \n"
" in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n"
" in float fade : TEXCOORD1, \n"
" uniform sampler2D texture : TEXUNIT0, \n"
" uniform float opacity, \n"
" uniform float4 diffuse, \n"
" uniform float4 emissive \n"
") \n"
"{ \n"
" oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n"
"}";
stars_fp->setSource(outStream5.str());
stars_fp->load();
stars_fp->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
stars_fp->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
night1_ent->getSubEntity(3)->getMaterial()->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName());
// Atmosphere (day)
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif");
ModVertexAlpha(atmosphere_ent, 0);
atmosphere_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY);
mAtmosphereDay = mRootNode->createChildSceneNode();
mAtmosphereDay->attachObject(atmosphere_ent);
mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial();
// Atmosphere shader
HighLevelGpuProgramPtr vshader = mgr.createProgram("Atmosphere_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_VERTEX_PROGRAM);
vshader->setParameter("profiles", "vs_2_x arbvp1");
vshader->setParameter("entry_point", "main_vp");
StringUtil::StrStreamType outStream;
outStream <<
"void main_vp( \n"
" float4 position : POSITION, \n"
" in float4 color : COLOR, \n"
" out float4 oPosition : POSITION, \n"
" out float4 oColor : COLOR, \n"
" uniform float4 emissive, \n"
" uniform float4x4 worldViewProj \n"
") \n"
"{ \n"
" oPosition = mul( worldViewProj, position ); \n"
" oColor = color * emissive; \n"
"}";
vshader->setSource(outStream.str());
vshader->load();
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
vshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
// Clouds
NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif");
Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif");
clouds_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+5);
SceneNode* clouds_node = mRootNode->createChildSceneNode();
clouds_node->attachObject(clouds_ent);
mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial();
// Clouds vertex shader
HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_VERTEX_PROGRAM);
vshader2->setParameter("profiles", "vs_2_x arbvp1");
vshader2->setParameter("entry_point", "main_vp");
StringUtil::StrStreamType outStream3;
outStream3 <<
"void main_vp( \n"
" float4 position : POSITION, \n"
" in float4 color : COLOR, \n"
" out float4 oColor : TEXCOORD1, \n"
" in float2 uv : TEXCOORD0, \n"
" out float2 oUV : TEXCOORD0, \n"
" out float4 oPosition : POSITION, \n"
" uniform float4x4 worldViewProj \n"
") \n"
"{ \n"
" oUV = uv; \n"
" oColor = color; \n"
" oPosition = mul( worldViewProj, position ); \n"
"}";
vshader2->setSource(outStream3.str());
vshader2->load();
vshader2->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
mCloudMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader2->getName());
// Clouds fragment shader
mCloudFragmentShader = mgr.createProgram("Clouds_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_FRAGMENT_PROGRAM);
mCloudFragmentShader->setParameter("profiles", "ps_2_x arbfp1");
mCloudFragmentShader->setParameter("entry_point", "main_fp");
StringUtil::StrStreamType outStream2;
outStream2 <<
"void main_fp( \n"
" in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n"
" in float4 color : TEXCOORD1, \n"
" uniform sampler2D texture : TEXUNIT0, \n"
" uniform sampler2D secondTexture : TEXUNIT1, \n"
" uniform float transitionFactor, \n"
" uniform float time, \n"
" uniform float speed, \n"
" uniform float opacity, \n"
" uniform float4 emissive \n"
") \n"
"{ \n"
" uv += float2(1,1) * time * speed * "<<CLOUD_SPEED<<"; \n" // Scroll in x,y direction
" float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n"
" oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n"
"}";
mCloudFragmentShader->setSource(outStream2.str());
mCloudFragmentShader->load();
mCloudFragmentShader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
mCloudMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(mCloudFragmentShader->getName());
setCloudsOpacity(0.75);
ModVertexAlpha(clouds_ent, 1);
// I'm not sure if the materials are being used by any other objects
// Make a unique "modifiable" copy of the materials to be sure
mCloudMaterial = mCloudMaterial->clone("Clouds");
clouds_ent->getSubEntity(0)->setMaterial(mCloudMaterial);
mAtmosphereMaterial = mAtmosphereMaterial->clone("Atmosphere");
atmosphere_ent->getSubEntity(0)->setMaterial(mAtmosphereMaterial);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 0.0);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0);
mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
mCloudMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("");
}
SkyManager::~SkyManager()
{
delete mSun;
delete mSunGlare;
delete mMasser;
delete mSecunda;
}
int SkyManager::getMasserPhase() const
{
return mMasser->getPhaseInt();
}
int SkyManager::getSecundaPhase() const
{
return mSecunda->getPhaseInt();
}
void SkyManager::update(float duration)
{
if (!mEnabled) return;
// UV Scroll the clouds
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", 1);
/// \todo improve this
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
// increase the strength of the sun glare effect depending
// on how directly the player is looking at the sun
if (mSunEnabled)
{
SkyManager* pSkyManager = NULL;
Vector3 sun = mSunGlare->getPosition();
sun = Vector3(sun.x, sun.z, -sun.y);
Vector3 cam = mViewport->getCamera()->getRealDirection();
const Degree angle = sun.angleBetween( cam );
float val = 1- (angle.valueDegrees() / 180.f);
val = (val*val*val*val)*2;
try
if (mGlareEnabled)
{
pSkyManager = new CaelumManager(pRenderWindow, pCamera, resDir);
mGlareFade += duration*3;
if (mGlareFade > 1) mGlareFade = 1;
}
catch (Ogre::Exception& e)
else
{
std::cout << "\nOGRE Exception when attempting to add sky: "
<< e.getFullDescription().c_str() << std::endl;
}
catch (std::exception& e)
{
std::cout << "\nException when attempting to add sky: "
<< e.what() << std::endl;
mGlareFade -= duration*3;
if (mGlareFade < 0.3) mGlareFade = 0;
}
return pSkyManager;
mSunGlare->setSize(val * (mGlareFade));
}
mSunGlare->setVisible(mGlareFade>0 && mSunEnabled);
mSun->setVisible(mSunEnabled);
mMasser->setVisible(mMasserEnabled);
mSecunda->setVisible(mSecundaEnabled);
}
void SkyManager::enable()
{
mRootNode->setVisible(true);
mEnabled = true;
}
void SkyManager::disable()
{
mRootNode->setVisible(false);
mEnabled = false;
}
void SkyManager::setMoonColour (bool red)
{
mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784)
: ColourValue(1.0, 1.0, 1.0));
}
void SkyManager::setCloudsOpacity(float opacity)
{
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity));
}
void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
{
if (mClouds != weather.mCloudTexture)
{
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture);
mClouds = weather.mCloudTexture;
}
if (mNextClouds != weather.mNextCloudTexture)
{
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName("textures\\"+weather.mNextCloudTexture);
mNextClouds = weather.mNextCloudTexture;
}
if (mCloudBlendFactor != weather.mCloudBlendFactor)
{
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("transitionFactor", Real(weather.mCloudBlendFactor));
mCloudBlendFactor = weather.mCloudBlendFactor;
}
if (mCloudOpacity != weather.mCloudOpacity)
{
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(weather.mCloudOpacity));
mCloudOpacity = weather.mCloudOpacity;
}
if (mCloudColour != weather.mSunColor)
{
ColourValue clr( weather.mSunColor.r*0.7 + weather.mAmbientColor.r*0.7,
weather.mSunColor.g*0.7 + weather.mAmbientColor.g*0.7,
weather.mSunColor.b*0.7 + weather.mAmbientColor.b*0.7);
mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(clr);
mCloudColour = weather.mSunColor;
}
if (mSkyColour != weather.mSkyColor)
{
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(weather.mSkyColor);
mSkyColour = weather.mSkyColor;
}
if (mCloudSpeed != weather.mCloudSpeed)
{
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("speed", Real(weather.mCloudSpeed));
mCloudSpeed = weather.mCloudSpeed;
}
if (weather.mNight && mStarsOpacity != weather.mNightFade)
{
for (int i=0; i<7; ++i)
mStarsMaterials[i]->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, weather.mNightFade);
mStarsOpacity = weather.mNightFade;
}
float strength;
float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length());
if (timeofday_angle <= 0.44)
strength = timeofday_angle/0.44f;
else
strength = 1.f;
mSunGlare->setVisibility(weather.mGlareView * strength);
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
}
void SkyManager::setGlare(bool glare)
{
mGlareEnabled = glare;
}
Vector3 SkyManager::getRealSunPos()
{
return mSun->getNode()->_getDerivedPosition();
}
void SkyManager::sunEnable()
{
mSunEnabled = true;
}
void SkyManager::sunDisable()
{
mSunEnabled = false;
}
void SkyManager::setSunDirection(const Vector3& direction)
{
mSun->setPosition(direction);
mSunGlare->setPosition(direction);
}
void SkyManager::setMasserDirection(const Vector3& direction)
{
mMasser->setPosition(direction);
}
void SkyManager::setSecundaDirection(const Vector3& direction)
{
mSecunda->setPosition(direction);
}
void SkyManager::masserEnable()
{
mMasserEnabled = true;
}
void SkyManager::secundaEnable()
{
mSecundaEnabled = true;
}
void SkyManager::masserDisable()
{
mMasserEnabled = false;
}
void SkyManager::secundaDisable()
{
mSecundaEnabled = false;
}
void SkyManager::setThunder(const float factor)
{
if (factor > 0.f)
{
mThunderOverlay->show();
mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, factor*0.6);
}
else
mThunderOverlay->hide();
}
void SkyManager::setMasserFade(const float fade)
{
mMasser->setVisibility(fade);
}
void SkyManager::setSecundaFade(const float fade)
{
mSecunda->setVisibility(fade);
}
void SkyManager::setHour(double hour)
{
mHour = hour;
}
void SkyManager::setDate(int day, int month)
{
mDay = day;
mMonth = month;
}

@ -1,40 +1,211 @@
#ifndef _GAME_RENDER_SKY_H
#define _GAME_RENDER_SKY_H
#include <boost/filesystem.hpp>
#include <OgreVector3.h>
#include <OgreString.h>
#include <OgreMaterial.h>
#include <OgreColourValue.h>
#include <OgreHighLevelGpuProgram.h>
#include "sky.hpp"
#include "../mwworld/weather.hpp"
namespace Ogre
{
class RenderWindow;
class SceneNode;
class Camera;
class Viewport;
class SceneManager;
class Entity;
class BillboardSet;
class TextureUnitState;
class Overlay;
}
namespace MWRender
{
///
/// Interface for the sky rendering system
///
class BillboardObject
{
public:
BillboardObject( const Ogre::String& textureName,
const float size,
const Ogre::Vector3& position,
Ogre::SceneNode* rootNode
);
BillboardObject();
void setColour(const Ogre::ColourValue& pColour);
void setPosition(const Ogre::Vector3& pPosition);
void setVisible(const bool visible);
void setRenderQueue(unsigned int id);
void setSize(const float size);
Ogre::Vector3 getPosition() const;
void setVisibility(const float visibility);
Ogre::SceneNode* getNode();
protected:
virtual void init(const Ogre::String& textureName,
const float size,
const Ogre::Vector3& position,
Ogre::SceneNode* rootNode);
Ogre::SceneNode* mNode;
Ogre::MaterialPtr mMaterial;
Ogre::BillboardSet* mBBSet;
};
/*
* The moons need a seperate class because of their shader (which allows them to be partially transparent)
*/
class Moon : public BillboardObject
{
public:
Moon( const Ogre::String& textureName,
const float size,
const Ogre::Vector3& position,
Ogre::SceneNode* rootNode
);
enum Phase
{
Phase_New = 0,
Phase_WaxingCrescent,
Phase_WaxingHalf,
Phase_WaxingGibbous,
Phase_Full,
Phase_WaningGibbous,
Phase_WaningHalf,
Phase_WaningCrescent
};
enum Type
{
Type_Masser = 0,
Type_Secunda
};
void setPhase(const Phase& phase);
void setType(const Type& type);
Phase getPhase() const;
unsigned int getPhaseInt() const;
private:
Type mType;
Phase mPhase;
};
class SkyManager
{
public:
static SkyManager* create (Ogre::RenderWindow* pRenderWindow,
Ogre::Camera* pCamera,
const boost::filesystem::path& resDir);
virtual ~SkyManager() {}
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera);
~SkyManager();
void update(float duration);
void enable();
void disable();
void setHour (double hour);
///< will be called even when sky is disabled.
void setDate (int day, int month);
///< will be called even when sky is disabled.
int getMasserPhase() const;
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
/// 3 waxing or waning gibbous, 4 full moon
int getSecundaPhase() const;
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
/// 3 waxing or waning gibbous, 4 full moon
void setMoonColour (bool red);
///< change Secunda colour to red
void setCloudsOpacity(float opacity);
///< change opacity of the clouds
void setWeather(const MWWorld::WeatherResult& weather);
void sunEnable();
void sunDisable();
void setSunDirection(const Ogre::Vector3& direction);
void setMasserDirection(const Ogre::Vector3& direction);
void setSecundaDirection(const Ogre::Vector3& direction);
void setMasserFade(const float fade);
void setSecundaFade(const float fade);
void masserEnable();
void masserDisable();
void secundaEnable();
void secundaDisable();
void setThunder(const float factor);
void setGlare(bool glare);
Ogre::Vector3 getRealSunPos();
private:
float mHour;
int mDay;
int mMonth;
BillboardObject* mSun;
BillboardObject* mSunGlare;
Moon* mMasser;
Moon* mSecunda;
Ogre::Viewport* mViewport;
Ogre::SceneNode* mRootNode;
Ogre::SceneManager* mSceneMgr;
Ogre::SceneNode* mAtmosphereDay;
Ogre::SceneNode* mAtmosphereNight;
Ogre::MaterialPtr mCloudMaterial;
Ogre::MaterialPtr mAtmosphereMaterial;
Ogre::MaterialPtr mStarsMaterials[7];
virtual void enable() = 0;
Ogre::HighLevelGpuProgramPtr mCloudFragmentShader;
virtual void disable() = 0;
// remember some settings so we don't have to apply them again if they didnt change
Ogre::String mClouds;
Ogre::String mNextClouds;
float mCloudBlendFactor;
float mCloudOpacity;
float mCloudSpeed;
float mStarsOpacity;
Ogre::ColourValue mCloudColour;
Ogre::ColourValue mSkyColour;
virtual void setHour (double hour) = 0;
Ogre::Overlay* mThunderOverlay;
Ogre::TextureUnitState* mThunderTextureUnit;
virtual void setDate (int day, int month) = 0;
float mRemainingTransitionTime;
virtual int getMasserPhase() const = 0;
float mGlareFade;
virtual int getSecundaPhase() const = 0;
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
virtual void setMoonColour (bool red) = 0;
bool mEnabled;
bool mGlareEnabled;
bool mSunEnabled;
bool mMasserEnabled;
bool mSecundaEnabled;
};
}

@ -11,7 +11,7 @@
#include "../mwworld/manualref.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerutil.hpp"
#include "../mwworld/containerstore.hpp"
#include "interpretercontext.hpp"
#include "ref.hpp"
@ -45,8 +45,7 @@ namespace MWScript
ref.getPtr().getRefData().setCount (count);
MWWorld::Class::get (ref.getPtr()).insertIntoContainer (ref.getPtr(),
MWWorld::Class::get (ptr).getContainerStore (ptr));
MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr());
}
};
@ -59,25 +58,16 @@ namespace MWScript
{
MWWorld::Ptr ptr = R()(runtime);
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
std::vector<MWWorld::Ptr> list;
MWWorld::listItemsInContainer (item,
MWWorld::Class::get (ptr).getContainerStore (ptr),
context.getWorld().getStore(), list);
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
Interpreter::Type_Integer sum = 0;
for (std::vector<MWWorld::Ptr>::iterator iter (list.begin()); iter!=list.end();
++iter)
{
sum += iter->getRefData().getCount();
}
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
if (iter->getCellRef().refID==item)
sum += iter->getRefData().getCount();
runtime.push (sum);
}
@ -92,9 +82,6 @@ namespace MWScript
{
MWWorld::Ptr ptr = R()(runtime);
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
@ -104,25 +91,23 @@ namespace MWScript
if (count<0)
throw std::runtime_error ("second argument for RemoveItem must be non-negative");
std::vector<MWWorld::Ptr> list;
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
MWWorld::listItemsInContainer (item,
MWWorld::Class::get (ptr).getContainerStore (ptr),
context.getWorld().getStore(), list);
for (std::vector<MWWorld::Ptr>::iterator iter (list.begin());
iter!=list.end() && count;
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count;
++iter)
{
if (iter->getRefData().getCount()<=count)
{
count -= iter->getRefData().getCount();
iter->getRefData().setCount (0);
}
else
if (iter->getCellRef().refID==item)
{
iter->getRefData().setCount (iter->getRefData().getCount()-count);
count = 0;
if (iter->getRefData().getCount()<=count)
{
count -= iter->getRefData().getCount();
iter->getRefData().setCount (0);
}
else
{
iter->getRefData().setCount (iter->getRefData().getCount()-count);
count = 0;
}
}
}

@ -116,4 +116,10 @@ op 0x2000137: GetButtonPressed
op 0x2000138: SkipAnim
op 0x2000139: SkipAnim, expplicit reference
op 0x200013a: AddTopic
opcodes 0x200013b-0x3ffffff unused
op 0x200013b: twf
op 0x200013c: FadeIn
op 0x200013d: FadeOut
op 0x200013e: FadeTo
op 0x200013f: GetCurrentWeather
op 0x2000140: ChangeWeather
opcodes 0x2000141-0x3ffffff unused

@ -103,7 +103,75 @@ namespace MWScript
context.getWorld().toggleRenderMode (MWWorld::World::Render_CollisionDebug);
context.report (enabled ?
"Collsion Mesh Rendering -> On" : "Collision Mesh Rendering -> Off");
"Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off");
}
};
class OpToggleWireframe : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
bool enabled =
context.getWorld().toggleRenderMode (MWWorld::World::Render_Wireframe);
context.report (enabled ?
"Wireframe Rendering -> On" : "Wireframe Rendering -> Off");
}
};
class OpFadeIn : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
Interpreter::Type_Float time = runtime[0].mFloat;
runtime.pop();
context.getWorld().getFader()->fadeIn(time);
}
};
class OpFadeOut : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
Interpreter::Type_Float time = runtime[0].mFloat;
runtime.pop();
context.getWorld().getFader()->fadeOut(time);
}
};
class OpFadeTo : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
Interpreter::Type_Float alpha = runtime[0].mFloat;
runtime.pop();
Interpreter::Type_Float time = runtime[0].mFloat;
runtime.pop();
context.getWorld().getFader()->fadeTo(alpha, time);
}
};
@ -115,6 +183,10 @@ namespace MWScript
const int opcodeUnlock = 0x200008c;
const int opcodeUnlockExplicit = 0x200008d;
const int opcodeToggleCollisionDebug = 0x2000132;
const int opcodeToggleWireframe = 0x200013b;
const int opcodeFadeIn = 0x200013c;
const int opcodeFadeOut = 0x200013d;
const int opcodeFadeTo = 0x200013e;
void registerExtensions (Compiler::Extensions& extensions)
{
@ -127,6 +199,11 @@ namespace MWScript
extensions.registerInstruction ("togglecollisiongrid", "", opcodeToggleCollisionDebug);
extensions.registerInstruction ("tcb", "", opcodeToggleCollisionDebug);
extensions.registerInstruction ("tcg", "", opcodeToggleCollisionDebug);
extensions.registerInstruction ("twf", "", opcodeToggleWireframe);
extensions.registerInstruction ("togglewireframe", "", opcodeToggleWireframe);
extensions.registerInstruction ("fadein", "f", opcodeFadeIn);
extensions.registerInstruction ("fadeout", "f", opcodeFadeOut);
extensions.registerInstruction ("fadeto", "ff", opcodeFadeTo);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
@ -139,6 +216,10 @@ namespace MWScript
interpreter.installSegment5 (opcodeUnlock, new OpUnlock<ImplicitRef>);
interpreter.installSegment5 (opcodeUnlockExplicit, new OpUnlock<ExplicitRef>);
interpreter.installSegment5 (opcodeToggleCollisionDebug, new OpToggleCollisionDebug);
interpreter.installSegment5 (opcodeToggleWireframe, new OpToggleWireframe);
interpreter.installSegment5 (opcodeFadeIn, new OpFadeIn);
interpreter.installSegment5 (opcodeFadeOut, new OpFadeOut);
interpreter.installSegment5 (opcodeFadeTo, new OpFadeTo);
}
}
}

@ -80,11 +80,45 @@ namespace MWScript
}
};
class OpGetCurrentWeather : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
runtime.push (context.getWorld().getCurrentWeather());
}
};
class OpChangeWeather : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
std::string region = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Integer id = runtime[0].mInteger;
runtime.pop();
context.getWorld().changeWeather(region, id);
}
};
const int opcodeToggleSky = 0x2000021;
const int opcodeTurnMoonWhite = 0x2000022;
const int opcodeTurnMoonRed = 0x2000023;
const int opcodeGetMasserPhase = 0x2000024;
const int opcodeGetSecundaPhase = 0x2000025;
const int opcodeGetCurrentWeather = 0x200013f;
const int opcodeChangeWeather = 0x2000140;
void registerExtensions (Compiler::Extensions& extensions)
{
@ -92,8 +126,10 @@ namespace MWScript
extensions.registerInstruction ("ts", "", opcodeToggleSky);
extensions.registerInstruction ("turnmoonwhite", "", opcodeTurnMoonWhite);
extensions.registerInstruction ("turnmoonred", "", opcodeTurnMoonRed);
extensions.registerInstruction ("changeweather", "Sl", opcodeChangeWeather);
extensions.registerFunction ("getmasserphase", 'l', "", opcodeGetMasserPhase);
extensions.registerFunction ("getsecundaphase", 'l', "", opcodeGetSecundaPhase);
extensions.registerFunction ("getcurrentweather", 'l', "", opcodeGetCurrentWeather);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
@ -103,6 +139,8 @@ namespace MWScript
interpreter.installSegment5 (opcodeTurnMoonRed, new OpTurnMoonRed);
interpreter.installSegment5 (opcodeGetMasserPhase, new OpGetMasserPhase);
interpreter.installSegment5 (opcodeGetSecundaPhase, new OpGetSecundaPhase);
interpreter.installSegment5 (opcodeGetCurrentWeather, new OpGetCurrentWeather);
interpreter.installSegment5 (opcodeChangeWeather, new OpChangeWeather);
}
}
}

@ -4,8 +4,6 @@
#include <algorithm>
#include <map>
using namespace std;
#include <OgreRoot.h>
#include <openengine/sound/sndmanager.hpp>
@ -15,6 +13,7 @@ using namespace std;
#include <components/file_finder/file_finder.hpp>
#include <components/esm_store/store.hpp>
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
#include "../mwworld/player.hpp"
@ -90,24 +89,28 @@ namespace MWSound
// relative to the sound dir, and translates them into full paths
// of existing files in the filesystem, if they exist.
bool FSstrict;
FileFinder::FileFinder files;
FileFinder::FileFinderStrict strict;
FileFinder::FileFinder musicpath;
FileFinder::FileFinderStrict musicpathStrict;
SoundImpl(Ogre::Root *root, Ogre::Camera *camera,
const ESMS::ESMStore &str,
const std::string &soundDir, const std::string &musicDir, bool fsstrict)
FileFinder::LessTreeFileFinder files;
FileFinder::StrictTreeFileFinder strict;
FileFinder::LessTreeFileFinder musicpath;
FileFinder::StrictTreeFileFinder musicpathStrict;
SoundImpl(Ogre::Root *root, Ogre::Camera *camera, const ESMS::ESMStore &str,
const Files::PathContainer& soundDir,
const Files::PathContainer& musicDir,
bool fsstrict)
: mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY)))
, updater(mgr)
, cameraTracker(mgr)
, store(str)
, files(soundDir), strict(soundDir)
,musicpath(musicDir), musicpathStrict(musicDir)
, FSstrict(fsstrict)
, files(soundDir)
, strict(soundDir)
, musicpath(musicDir)
, musicpathStrict(musicDir)
{
FSstrict = fsstrict;
cout << "Sound output: " << SOUND_OUT << endl;
cout << "Sound decoder: " << SOUND_IN << endl;
std::cout << "Sound output: " << SOUND_OUT << std::endl;
std::cout << "Sound decoder: " << SOUND_IN << std::endl;
// Attach the camera to the camera tracker
cameraTracker.followCamera(camera);
@ -136,36 +139,49 @@ namespace MWSound
bool hasFile(const std::string &str, bool music = false)
{
if(FSstrict == false)
bool found = false;
if(!FSstrict)
{
if(music)
{
if(musicpath.has(str)) return true;
found = musicpath.has(str);
// Not found? Try with .mp3
return musicpath.has(toMp3(str));
if (!found)
{
found = musicpath.has(toMp3(str));
}
}
else
{
if(files.has(str)) return true;
return files.has(toMp3(str));
found = files.has(str);
if (!found)
{
found = files.has(toMp3(str));
}
}
}
else
{
if(music)
{
if(musicpathStrict.has(str)) return true;
found = musicpathStrict.has(str);
// Not found? Try with .mp3
return musicpathStrict.has(toMp3(str));
if (!found)
{
found = musicpathStrict.has(toMp3(str));
}
}
else
{
if(strict.has(str)) return true;
return strict.has(toMp3(str));
found = strict.has(str);
if (!found)
{
found = strict.has(toMp3(str));
}
}
}
return found;
}
// Convert a Morrowind sound path (eg. Fx\funny.wav) to full path
@ -258,13 +274,13 @@ namespace MWSound
}
catch(...)
{
cout << "Error loading " << file << ", skipping.\n";
std::cout << "Error loading " << file << ", skipping.\n";
}
}
// Clears all the sub-elements of a given iterator, and then
// removes it from 'sounds'.
void clearAll(PtrMap::iterator it)
void clearAll(PtrMap::iterator& it)
{
IDMap::iterator sit = it->second.begin();
@ -362,9 +378,9 @@ namespace MWSound
}
}
}
};
}; /* SoundImpl */
void SoundManager::streamMusicFull (const std::string& filename)
void SoundManager::streamMusicFull(const std::string& filename)
{
if(!mData) return;
@ -381,20 +397,24 @@ namespace MWSound
}
SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera,
const ESMS::ESMStore &store,
boost::filesystem::path dataDir,
bool useSound, bool fsstrict, MWWorld::Environment& environment)
: mData(NULL), fsStrict (fsstrict), mEnvironment (environment)
const ESMS::ESMStore &store, const Files::PathContainer& dataDirs,
bool useSound, bool fsstrict, MWWorld::Environment& environment)
: mData(NULL)
, fsStrict(fsstrict)
, mEnvironment(environment)
{
MP3Lookup(dataDir / "Music/Explore/");
if(useSound)
mData = new SoundImpl(root, camera, store, (dataDir / "Sound").string(), (dataDir / "Music").string(), fsstrict);
for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
{
MP3Lookup((*it) / "Music/Explore/");
}
if(useSound)
{
mData = new SoundImpl(root, camera, store, dataDirs /* Sound */, dataDirs /* Music */, fsstrict);
}
test.name = "";
total = 0;
}
SoundManager::~SoundManager()
@ -407,14 +427,12 @@ namespace MWSound
{
if(mData->hasFile(filename, true))
{
std::string fullpath = mData->convertPath(filename, true);
streamMusicFull(fullpath);
streamMusicFull(mData->convertPath(filename, true));
}
}
void SoundManager::MP3Lookup(boost::filesystem::path dir)
{
void SoundManager::MP3Lookup(const boost::filesystem::path& dir)
{
boost::filesystem::directory_iterator dir_iter(dir), dir_end;
std::string mp3extension = ".mp3";
@ -425,35 +443,30 @@ namespace MWSound
files.push_back(*dir_iter);
}
}
}
}
void SoundManager::startRandomTitle()
{
std::vector<boost::filesystem::path>::iterator fileIter;
if(files.size() > 0)
{
if(!files.empty())
{
fileIter = files.begin();
srand ( time(NULL) );
Files::PathContainer::iterator fileIter = files.begin();
srand( time(NULL) );
int r = rand() % files.size() + 1; //old random code
for(int i = 1; i < r; i++)
{
fileIter++;
}
std::advance(fileIter, r - 1);
std::string music = fileIter->string();
std::cout << "Playing " << music << "\n";
try
{
std::cout << "Playing " << music << "\n";
streamMusicFull(music);
}
catch(std::exception &e)
catch (std::exception &e)
{
std::cout << " Music Error: " << e.what() << "\n";
}
}
}
}
bool SoundManager::isMusicPlaying()
{
@ -465,14 +478,12 @@ namespace MWSound
return test;
}
SoundManager::SoundImpl SoundManager::getMData()
SoundManager::SoundImpl SoundManager::getMData()
{
// bool test = mData->music->isPlaying();
return *mData;
}
void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename)
{
// The range values are not tested
@ -480,7 +491,7 @@ namespace MWSound
if(mData->hasFile(filename))
mData->add(mData->convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false);
else
cout << "Sound file " << filename << " not found, skipping.\n";
std::cout << "Sound file " << filename << " not found, skipping.\n";
}
bool SoundManager::sayDone (MWWorld::Ptr ptr) const
@ -490,20 +501,20 @@ namespace MWSound
}
void SoundManager::playSound (const std::string& soundId, float volume, float pitch)
void SoundManager::playSound(const std::string& soundId, float volume, float pitch)
{
if(!mData) return;
// Play and forget
float min, max;
const std::string &file = mData->lookup(soundId, volume, min, max);
if(file != "")
{
if (file != "")
{
SoundPtr snd = mData->mgr->load(file);
snd->setVolume(volume);
snd->setRange(min,max);
snd->setPitch(pitch);
snd->play();
}
}
}
void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId,
@ -514,7 +525,7 @@ namespace MWSound
// Look up the sound in the ESM data
float min, max;
const std::string &file = mData->lookup(soundId, volume, min, max);
if(file != "")
if (file != "")
mData->add(file, ptr, soundId, volume, pitch, min, max, loop);
}
@ -541,18 +552,19 @@ namespace MWSound
void SoundManager::updateObject(MWWorld::Ptr ptr)
{
if(!mData) return;
mData->updatePositions(ptr);
if (mData != NULL)
{
mData->updatePositions(ptr);
}
}
void SoundManager::update (float duration)
{
std::string effect;
MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell();
//If the region has changed
if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10){
if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10)
{
timer.restart();
if (test.name != current->cell->region)
{
@ -564,11 +576,12 @@ namespace MWSound
{
std::vector<ESM::Region::SoundRef>::iterator soundIter = test.soundList.begin();
//mEnvironment.mSoundManager
if(total == 0){
while (!(soundIter == test.soundList.end()))
if(total == 0)
{
while (soundIter != test.soundList.end())
{
ESM::NAME32 go = soundIter->sound;
int chance = (int) soundIter->chance;
//ESM::NAME32 go = soundIter->sound;
//std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
soundIter++;
total += chance;
@ -578,7 +591,7 @@ namespace MWSound
int r = rand() % total; //old random code
int pos = 0;
soundIter = test.soundList.begin();
while (!(soundIter == test.soundList.end()))
while (soundIter != test.soundList.end())
{
const ESM::NAME32 go = soundIter->sound;
int chance = (int) soundIter->chance;
@ -586,13 +599,11 @@ namespace MWSound
soundIter++;
if( r - pos < chance)
{
effect = go.name;
//play sound
std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
mEnvironment.mSoundManager->playSound(effect, 20.0, 1.0);
mEnvironment.mSoundManager->playSound(go.name, 20.0, 1.0);
break;
}
pos += chance;
}

@ -2,14 +2,15 @@
#define GAME_SOUND_SOUNDMANAGER_H
#include <string>
#include <map>
#include <boost/filesystem.hpp>
#include <boost/timer.hpp>
#include "../mwworld/ptr.hpp"
#include <openengine/sound/sndmanager.hpp>
#include <components/files/multidircollection.hpp>
#include <boost/timer.hpp>
namespace Ogre
{
@ -37,7 +38,7 @@ namespace MWSound
struct SoundImpl;
SoundImpl *mData;
std::vector<boost::filesystem::path> files;
Files::PathContainer files;
bool fsStrict;
MWWorld::Environment& mEnvironment;
@ -52,7 +53,7 @@ namespace MWSound
public:
SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store,
boost::filesystem::path dataDir, bool useSound, bool fsstrict,
const Files::PathContainer& dataDir, bool useSound, bool fsstrict,
MWWorld::Environment& environment);
~SoundManager();
@ -61,7 +62,7 @@ namespace MWSound
/// \param filename name of a sound file in "Music/" in the data directory.
void startRandomTitle();
void MP3Lookup(boost::filesystem::path dir);
void MP3Lookup(const boost::filesystem::path& dir);
bool isMusicPlaying();

@ -4,6 +4,7 @@
#include "class.hpp"
#include "environment.hpp"
#include "world.hpp"
#include "containerstore.hpp"
namespace MWWorld
{
@ -14,8 +15,7 @@ namespace MWWorld
// insert into player's inventory
MWWorld::Ptr player = environment.mWorld->getPtr ("player", true);
MWWorld::Class::get (mObject).insertIntoContainer (mObject,
MWWorld::Class::get (player).getContainerStore (player));
MWWorld::Class::get (player).getContainerStore (player).add (mObject);
// remove from world
environment.mWorld->deleteObject (mObject);

@ -63,9 +63,10 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y)
result = mExteriors.insert (std::make_pair (
std::make_pair (x, y), Ptr::CellStore (cell))).first;
}
if (result->second.mState!=Ptr::CellStore::State_Loaded)
result->second.load (mStore, mReader);
}
return &result->second;
}
@ -79,9 +80,10 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name)
const ESM::Cell *cell = mStore.cells.findInt (name);
result = mInteriors.insert (std::make_pair (name, Ptr::CellStore (cell))).first;
}
if (result->second.mState!=Ptr::CellStore::State_Loaded)
result->second.load (mStore, mReader);
}
return &result->second;
}

@ -7,6 +7,7 @@
#include "ptr.hpp"
#include "nullaction.hpp"
#include "containerstore.hpp"
namespace MWWorld
{
@ -71,16 +72,11 @@ namespace MWWorld
return boost::shared_ptr<Action> (new NullAction);
}
ContainerStore<RefData>& Class::getContainerStore (const Ptr& ptr) const
ContainerStore& Class::getContainerStore (const Ptr& ptr) const
{
throw std::runtime_error ("class does not have a container store");
}
void Class::insertIntoContainer (const Ptr& ptr, ContainerStore<RefData>& containerStore) const
{
throw std::runtime_error ("class does not support inserting into a container");
}
void Class::lock (const Ptr& ptr, int lockLevel) const
{
throw std::runtime_error ("class does not support locking");

@ -7,11 +7,11 @@
#include <boost/shared_ptr.hpp>
#include "action.hpp"
#include "containerstore.hpp"
#include "refdata.hpp"
#include "../mwrender/renderinginterface.hpp"
#include "physicssystem.hpp"
#include "../mwrender/renderinginterface.hpp"
namespace Ogre
{
class Vector3;
@ -33,6 +33,7 @@ namespace MWWorld
{
class Ptr;
class Environment;
class ContainerStore;
/// \brief Base class for referenceable esm records
class Class
@ -61,8 +62,6 @@ namespace MWWorld
///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval
/// (default implementation: throw an exception)
virtual void insertObjectRendering (const Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
virtual void insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const;
///< Add reference into a cell for rendering (default implementation: don't render anything).
@ -105,15 +104,10 @@ namespace MWWorld
///< Generate action for using via inventory menu (default implementation: return a
/// null action).
virtual ContainerStore<RefData>& getContainerStore (const Ptr& ptr) const;
virtual ContainerStore& getContainerStore (const Ptr& ptr) const;
///< Return container store or throw an exception, if class does not have a
/// container store (default implementation: throw an exceoption)
virtual void insertIntoContainer (const Ptr& ptr, ContainerStore<RefData>& containerStore)
const;
///< Insert into a container or throw an exception, if class does not support inserting into
/// a container.
virtual void lock (const Ptr& ptr, int lockLevel) const;
///< Lock object (default implementation: throw an exception)

@ -0,0 +1,342 @@
#include "containerstore.hpp"
#include <cassert>
#include <typeinfo>
#include <stdexcept>
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::begin (int mask)
{
return ContainerStoreIterator (mask, this);
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end()
{
return ContainerStoreIterator (this);
}
void MWWorld::ContainerStore::add (const Ptr& ptr)
{
/// \todo implement item stocking
switch (getType (ptr))
{
case Type_Potion: potions.list.push_back (*ptr.get<ESM::Potion>()); break;
case Type_Apparatus: appas.list.push_back (*ptr.get<ESM::Apparatus>()); break;
case Type_Armor: armors.list.push_back (*ptr.get<ESM::Armor>()); break;
case Type_Book: books.list.push_back (*ptr.get<ESM::Book>()); break;
case Type_Clothing: clothes.list.push_back (*ptr.get<ESM::Clothing>()); break;
case Type_Ingredient: ingreds.list.push_back (*ptr.get<ESM::Ingredient>()); break;
case Type_Light: lights.list.push_back (*ptr.get<ESM::Light>()); break;
case Type_Lockpick: lockpicks.list.push_back (*ptr.get<ESM::Tool>()); break;
case Type_Miscellaneous: miscItems.list.push_back (*ptr.get<ESM::Miscellaneous>()); break;
case Type_Probe: probes.list.push_back (*ptr.get<ESM::Probe>()); break;
case Type_Repair: repairs.list.push_back (*ptr.get<ESM::Repair>()); break;
case Type_Weapon: weapons.list.push_back (*ptr.get<ESM::Weapon>()); break;
}
}
int MWWorld::ContainerStore::getType (const Ptr& ptr)
{
if (ptr.isEmpty())
throw std::runtime_error ("can't put a non-existent object into a container");
if (ptr.getTypeName()==typeid (ESM::Potion).name())
return Type_Potion;
if (ptr.getTypeName()==typeid (ESM::Apparatus).name())
return Type_Apparatus;
if (ptr.getTypeName()==typeid (ESM::Armor).name())
return Type_Armor;
if (ptr.getTypeName()==typeid (ESM::Book).name())
return Type_Book;
if (ptr.getTypeName()==typeid (ESM::Clothing).name())
return Type_Clothing;
if (ptr.getTypeName()==typeid (ESM::Ingredient).name())
return Type_Ingredient;
if (ptr.getTypeName()==typeid (ESM::Light).name())
return Type_Light;
if (ptr.getTypeName()==typeid (ESM::Tool).name())
return Type_Lockpick;
if (ptr.getTypeName()==typeid (ESM::Miscellaneous).name())
return Type_Miscellaneous;
if (ptr.getTypeName()==typeid (ESM::Probe).name())
return Type_Probe;
if (ptr.getTypeName()==typeid (ESM::Repair).name())
return Type_Repair;
if (ptr.getTypeName()==typeid (ESM::Weapon).name())
return Type_Weapon;
throw std::runtime_error (
"Object of type " + ptr.getTypeName() + " can not be placed into a container");
}
MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container)
: mType (-1), mMask (0), mContainer (container)
{}
MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStore *container)
: mType (0), mMask (mask), mContainer (container)
{
nextType();
}
void MWWorld::ContainerStoreIterator::incType()
{
if (mType==0)
mType = 1;
else if (mType!=-1)
{
mType <<= 1;
if (mType>ContainerStore::Type_Last)
mType = -1;
}
}
void MWWorld::ContainerStoreIterator::nextType()
{
while (mType!=-1)
{
incType();
if (mType & mMask)
if (resetIterator())
break;
}
}
bool MWWorld::ContainerStoreIterator::resetIterator()
{
switch (mType)
{
case ContainerStore::Type_Potion:
mPotion = mContainer->potions.list.begin();
return mPotion!=mContainer->potions.list.end();
case ContainerStore::Type_Apparatus:
mApparatus = mContainer->appas.list.begin();
return mApparatus!=mContainer->appas.list.end();
case ContainerStore::Type_Armor:
mArmor = mContainer->armors.list.begin();
return mArmor!=mContainer->armors.list.end();
case ContainerStore::Type_Book:
mBook = mContainer->books.list.begin();
return mBook!=mContainer->books.list.end();
case ContainerStore::Type_Clothing:
mClothing = mContainer->clothes.list.begin();
return mClothing!=mContainer->clothes.list.end();
case ContainerStore::Type_Ingredient:
mIngredient = mContainer->ingreds.list.begin();
return mIngredient!=mContainer->ingreds.list.end();
case ContainerStore::Type_Light:
mLight = mContainer->lights.list.begin();
return mLight!=mContainer->lights.list.end();
case ContainerStore::Type_Lockpick:
mLockpick = mContainer->lockpicks.list.begin();
return mLockpick!=mContainer->lockpicks.list.end();
case ContainerStore::Type_Miscellaneous:
mMiscellaneous = mContainer->miscItems.list.begin();
return mMiscellaneous!=mContainer->miscItems.list.end();
case ContainerStore::Type_Probe:
mProbe = mContainer->probes.list.begin();
return mProbe!=mContainer->probes.list.end();
case ContainerStore::Type_Repair:
mRepair = mContainer->repairs.list.begin();
return mRepair!=mContainer->repairs.list.end();
case ContainerStore::Type_Weapon:
mWeapon = mContainer->weapons.list.begin();
return mWeapon!=mContainer->weapons.list.end();
}
return false;
}
bool MWWorld::ContainerStoreIterator::incIterator()
{
switch (mType)
{
case ContainerStore::Type_Potion:
++mPotion;
return mPotion==mContainer->potions.list.end();
case ContainerStore::Type_Apparatus:
++mApparatus;
return mApparatus==mContainer->appas.list.end();
case ContainerStore::Type_Armor:
++mArmor;
return mArmor==mContainer->armors.list.end();
case ContainerStore::Type_Book:
++mBook;
return mBook==mContainer->books.list.end();
case ContainerStore::Type_Clothing:
++mClothing;
return mClothing==mContainer->clothes.list.end();
case ContainerStore::Type_Ingredient:
++mIngredient;
return mIngredient==mContainer->ingreds.list.end();
case ContainerStore::Type_Light:
++mLight;
return mLight==mContainer->lights.list.end();
case ContainerStore::Type_Lockpick:
++mLockpick;
return mLockpick==mContainer->lockpicks.list.end();
case ContainerStore::Type_Miscellaneous:
++mMiscellaneous;
return mMiscellaneous==mContainer->miscItems.list.end();
case ContainerStore::Type_Probe:
++mProbe;
return mProbe==mContainer->probes.list.end();
case ContainerStore::Type_Repair:
++mRepair;
return mRepair==mContainer->repairs.list.end();
case ContainerStore::Type_Weapon:
++mWeapon;
return mWeapon==mContainer->weapons.list.end();
}
return true;
}
MWWorld::Ptr *MWWorld::ContainerStoreIterator::operator->() const
{
mPtr = **this;
return &mPtr;
}
MWWorld::Ptr MWWorld::ContainerStoreIterator::operator*() const
{
switch (mType)
{
case ContainerStore::Type_Potion: return MWWorld::Ptr (&*mPotion, 0);
case ContainerStore::Type_Apparatus: return MWWorld::Ptr (&*mApparatus, 0);
case ContainerStore::Type_Armor: return MWWorld::Ptr (&*mArmor, 0);
case ContainerStore::Type_Book: return MWWorld::Ptr (&*mBook, 0);
case ContainerStore::Type_Clothing: return MWWorld::Ptr (&*mClothing, 0);
case ContainerStore::Type_Ingredient: return MWWorld::Ptr (&*mIngredient, 0);
case ContainerStore::Type_Light: return MWWorld::Ptr (&*mLight, 0);
case ContainerStore::Type_Lockpick: return MWWorld::Ptr (&*mLockpick, 0);
case ContainerStore::Type_Miscellaneous: return MWWorld::Ptr (&*mMiscellaneous, 0);
case ContainerStore::Type_Probe: return MWWorld::Ptr (&*mProbe, 0);
case ContainerStore::Type_Repair: return MWWorld::Ptr (&*mRepair, 0);
case ContainerStore::Type_Weapon: return MWWorld::Ptr (&*mWeapon, 0);
}
throw std::runtime_error ("invalid pointer");
}
MWWorld::ContainerStoreIterator& MWWorld::ContainerStoreIterator::operator++()
{
do
{
if (incIterator())
nextType();
}
while (mType!=-1 && !(**this).getRefData().getCount());
return *this;
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStoreIterator::operator++ (int)
{
ContainerStoreIterator iter (*this);
++*this;
return iter;
}
bool MWWorld::ContainerStoreIterator::isEqual (const ContainerStoreIterator& iter) const
{
assert (mContainer==iter.mContainer);
if (mType!=iter.mType)
return false;
switch (mType)
{
case ContainerStore::Type_Potion: return mPotion==iter.mPotion;
case ContainerStore::Type_Apparatus: return mApparatus==iter.mApparatus;
case ContainerStore::Type_Armor: return mArmor==iter.mArmor;
case ContainerStore::Type_Book: return mBook==iter.mBook;
case ContainerStore::Type_Clothing: return mClothing==iter.mClothing;
case ContainerStore::Type_Ingredient: return mIngredient==iter.mIngredient;
case ContainerStore::Type_Light: return mLight==iter.mLight;
case ContainerStore::Type_Lockpick: return mLockpick==iter.mLockpick;
case ContainerStore::Type_Miscellaneous: return mMiscellaneous==iter.mMiscellaneous;
case ContainerStore::Type_Probe: return mProbe==iter.mProbe;
case ContainerStore::Type_Repair: return mRepair==iter.mRepair;
case ContainerStore::Type_Weapon: return mWeapon==iter.mWeapon;
case -1: return true;
}
return false;
}
int MWWorld::ContainerStoreIterator::getType() const
{
return mType;
}
bool MWWorld::operator== (const ContainerStoreIterator& left, const ContainerStoreIterator& right)
{
return left.isEqual (right);
}
bool MWWorld::operator!= (const ContainerStoreIterator& left, const ContainerStoreIterator& right)
{
return !(left==right);
}

@ -3,24 +3,134 @@
#include <components/esm_store/cell_store.hpp>
#include "refdata.hpp"
#include "ptr.hpp"
namespace MWWorld
{
template<typename D>
struct ContainerStore
class ContainerStoreIterator;
class ContainerStore
{
ESMS::CellRefList<ESM::Potion, D> potions;
ESMS::CellRefList<ESM::Apparatus, D> appas;
ESMS::CellRefList<ESM::Armor, D> armors;
ESMS::CellRefList<ESM::Book, D> books;
ESMS::CellRefList<ESM::Clothing, D> clothes;
ESMS::CellRefList<ESM::Ingredient, D> ingreds;
ESMS::CellRefList<ESM::Light, D> lights;
ESMS::CellRefList<ESM::Tool, D> lockpicks;
ESMS::CellRefList<ESM::Miscellaneous, D> miscItems;
ESMS::CellRefList<ESM::Probe, D> probes;
ESMS::CellRefList<ESM::Repair, D> repairs;
ESMS::CellRefList<ESM::Weapon, D> weapons;
public:
static const int Type_Potion = 0x0001;
static const int Type_Apparatus = 0x0002;
static const int Type_Armor = 0x0004;
static const int Type_Book = 0x0008;
static const int Type_Clothing = 0x0010;
static const int Type_Ingredient = 0x0020;
static const int Type_Light = 0x0040;
static const int Type_Lockpick = 0x0080;
static const int Type_Miscellaneous = 0x0100;
static const int Type_Probe = 0x0200;
static const int Type_Repair = 0x0400;
static const int Type_Weapon = 0x0800;
static const int Type_Last = Type_Weapon;
static const int Type_All = 0xffff;
private:
ESMS::CellRefList<ESM::Potion, RefData> potions;
ESMS::CellRefList<ESM::Apparatus, RefData> appas;
ESMS::CellRefList<ESM::Armor, RefData> armors;
ESMS::CellRefList<ESM::Book, RefData> books;
ESMS::CellRefList<ESM::Clothing, RefData> clothes;
ESMS::CellRefList<ESM::Ingredient, RefData> ingreds;
ESMS::CellRefList<ESM::Light, RefData> lights;
ESMS::CellRefList<ESM::Tool, RefData> lockpicks;
ESMS::CellRefList<ESM::Miscellaneous, RefData> miscItems;
ESMS::CellRefList<ESM::Probe, RefData> probes;
ESMS::CellRefList<ESM::Repair, RefData> repairs;
ESMS::CellRefList<ESM::Weapon, RefData> weapons;
public:
ContainerStoreIterator begin (int mask = Type_All);
ContainerStoreIterator end();
void add (const Ptr& ptr);
///< Add the item pointed to by \a ptr to this container.
///
/// \note The item pointed to is not required to exist beyond this function call.
///
/// \attention Do not add items to an existing stack by increasing the count instead of
/// calling this function!
static int getType (const Ptr& ptr);
///< This function throws an exception, if ptr does not point to an object, that can be
/// put into a container.
friend class ContainerStoreIterator;
};
/// \brief Iteration over a subset of objects in a ContainerStore
///
/// \note The iterator will automatically skip over deleted objects.
class ContainerStoreIterator
{
int mType;
int mMask;
ContainerStore *mContainer;
mutable Ptr mPtr;
ESMS::CellRefList<ESM::Potion, RefData>::List::iterator mPotion;
ESMS::CellRefList<ESM::Apparatus, RefData>::List::iterator mApparatus;
ESMS::CellRefList<ESM::Armor, RefData>::List::iterator mArmor;
ESMS::CellRefList<ESM::Book, RefData>::List::iterator mBook;
ESMS::CellRefList<ESM::Clothing, RefData>::List::iterator mClothing;
ESMS::CellRefList<ESM::Ingredient, RefData>::List::iterator mIngredient;
ESMS::CellRefList<ESM::Light, RefData>::List::iterator mLight;
ESMS::CellRefList<ESM::Tool, RefData>::List::iterator mLockpick;
ESMS::CellRefList<ESM::Miscellaneous, RefData>::List::iterator mMiscellaneous;
ESMS::CellRefList<ESM::Probe, RefData>::List::iterator mProbe;
ESMS::CellRefList<ESM::Repair, RefData>::List::iterator mRepair;
ESMS::CellRefList<ESM::Weapon, RefData>::List::iterator mWeapon;
private:
ContainerStoreIterator (ContainerStore *container);
///< End-iterator
ContainerStoreIterator (int mask, ContainerStore *container);
///< Begin-iterator
void incType();
void nextType();
bool resetIterator();
///< Reset iterator for selected type.
///
/// \return Type not empty?
bool incIterator();
///< Increment iterator for selected type.
///
/// \return reached the end?
public:
Ptr *operator->() const;
Ptr operator*() const;
ContainerStoreIterator& operator++();
ContainerStoreIterator operator++ (int);
bool isEqual (const ContainerStoreIterator& iter) const;
int getType() const;
friend class ContainerStore;
};
bool operator== (const ContainerStoreIterator& left, const ContainerStoreIterator& right);
bool operator!= (const ContainerStoreIterator& left, const ContainerStoreIterator& right);
}
#endif

@ -1,43 +0,0 @@
#include "containerutil.hpp"
namespace
{
template<typename T>
void listItemsInContainerImp (const std::string& id,
ESMS::CellRefList<T, MWWorld::RefData>& containerStore,
const ESMS::RecListT<T>& store, std::vector<MWWorld::Ptr>& list)
{
if (const T *record = store.search (id))
{
for (typename ESMS::CellRefList<T, MWWorld::RefData>::List::iterator iter
(containerStore.list.begin());
iter!=containerStore.list.end(); ++iter)
{
if (iter->base==record)
list.push_back (MWWorld::Ptr (&*iter, 0));
}
}
}
}
namespace MWWorld
{
void listItemsInContainer (const std::string& id,
ContainerStore<MWWorld::RefData>& containerStore,
const ESMS::ESMStore& store, std::vector<Ptr>& list)
{
listItemsInContainerImp (id, containerStore.potions, store.potions, list);
listItemsInContainerImp (id, containerStore.appas, store.appas, list);
listItemsInContainerImp (id, containerStore.armors, store.armors, list);
listItemsInContainerImp (id, containerStore.books, store.books, list);
listItemsInContainerImp (id, containerStore.clothes, store.clothes, list);
listItemsInContainerImp (id, containerStore.ingreds, store.ingreds, list);
listItemsInContainerImp (id, containerStore.lights, store.lights, list);
listItemsInContainerImp (id, containerStore.lockpicks, store.lockpicks, list);
listItemsInContainerImp (id, containerStore.miscItems, store.miscItems, list);
listItemsInContainerImp (id, containerStore.probes, store.probes, list);
listItemsInContainerImp (id, containerStore.repairs, store.repairs, list);
listItemsInContainerImp (id, containerStore.weapons, store.weapons, list);
}
}

@ -1,20 +0,0 @@
#ifndef GAME_MWWORLD_CONTAINERUTIL_H
#define GAME_MWWORLD_CONTAINERUTIL_H
#include <string>
#include <vector>
#include <components/esm_store/store.hpp>
#include "containerstore.hpp"
#include "ptr.hpp"
#include "refdata.hpp"
namespace MWWorld
{
void listItemsInContainer (const std::string& id, ContainerStore<MWWorld::RefData>& containerStore,
const ESMS::ESMStore& store, std::vector<Ptr>& list);
///< append all references with the given id to list.
}
#endif

@ -82,6 +82,7 @@ namespace MWWorld
// initialise
ESM::CellRef& cellRef = mPtr.getCellRef();
cellRef.refID = name;
cellRef.refnum = -1;
cellRef.scale = 1;
cellRef.factIndex = 0;

@ -51,6 +51,17 @@ namespace MWWorld
return mEngine->rayTest(from,to);
}
bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to)
{
btVector3 _from, _to;
_from = btVector3(from.x, from.y, from.z);
_to = btVector3(to.x, to.y, to.z);
std::pair<std::string, float> result = mEngine->rayTest(_from, _to);
return !(result.first == "");
}
std::vector< std::pair<std::string, Ogre::Vector3> > PhysicsSystem::doPhysics (float duration,
const std::vector<std::pair<std::string, Ogre::Vector3> >& actors)
@ -109,7 +120,7 @@ namespace MWWorld
void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh,
const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position)
{
OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle);
OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle,scale);
mEngine->addRigidBody(body);
btTransform tr;
tr.setOrigin(btVector3(position.x,position.y,position.z));

@ -33,11 +33,15 @@ namespace MWWorld
void scaleObject (const std::string& handle, float scale);
bool toggleCollisionMode();
std::pair<std::string, float> getFacedHandle (MWWorld::World& world);
std::pair<std::string, float> getFacedHandle (MWWorld::World& world);
// cast ray, return true if it hit something
bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to);
void insertObjectPhysics(const MWWorld::Ptr& ptr, std::string model);
void insertActorPhysics(const MWWorld::Ptr&, std::string model);
void insertActorPhysics(const MWWorld::Ptr&, std::string model);
OEngine::Physic::PhysicEngine* getEngine();

@ -60,12 +60,12 @@ namespace MWWorld
std::cout << "Unloading cell\n";
ListHandles functor;
MWWorld::Ptr::CellStore* active = *iter;
active->forEach<ListHandles>(functor);
(*iter)->forEach<ListHandles>(functor);
{
@ -77,12 +77,14 @@ namespace MWWorld
mPhysics->removeObject (node->getName());
}
}
mRendering.removeCell(active);
mRendering.removeCell(*iter);
//mPhysics->removeObject("Unnamed_43");
mWorld->getLocalScripts().clearCell (active);
mEnvironment.mMechanicsManager->dropActors (active);
mEnvironment.mSoundManager->stopSound (active);
mActiveCells.erase(active);
mWorld->getLocalScripts().clearCell (*iter);
mEnvironment.mMechanicsManager->dropActors (*iter);
mEnvironment.mSoundManager->stopSound (*iter);
mActiveCells.erase(*iter);
}
@ -234,6 +236,9 @@ namespace MWWorld
mCurrentCell = cell;
playerCellChange (cell, position);
// adjust fog
mRendering.configureFog(*cell);
// Sky system
mWorld->adjustSky();

@ -0,0 +1,803 @@
#include "weather.hpp"
#include "world.hpp"
#include "player.hpp"
#include "../mwrender/renderingmanager.hpp"
#include "../mwsound/soundmanager.hpp"
#include <ctime>
#include <cstdlib>
#include <iostream>
#include <boost/algorithm/string.hpp>
using namespace Ogre;
using namespace MWWorld;
using namespace MWSound;
#define lerp(x, y) (x * (1-factor) + y * factor)
const std::string WeatherGlobals::mThunderSoundID0 = "Thunder0";
const std::string WeatherGlobals::mThunderSoundID1 = "Thunder1";
const std::string WeatherGlobals::mThunderSoundID2 = "Thunder2";
const std::string WeatherGlobals::mThunderSoundID3 = "Thunder3";
WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environment* env) :
mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0),
mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0)
{
mRendering = rendering;
mEnvironment = env;
#define clr(r,g,b) ColourValue(r/255.f, g/255.f, b/255.f)
/// \todo read these from Morrowind.ini
Weather clear;
clear.mCloudTexture = "tx_sky_clear.dds";
clear.mCloudsMaximumPercent = 1.0;
clear.mTransitionDelta = 0.015;
clear.mSkySunriseColor = clr(118, 141, 164);
clear.mSkyDayColor = clr(95, 135, 203);
clear.mSkySunsetColor = clr(56, 89, 129);
clear.mSkyNightColor = clr(9, 10, 11);
clear.mFogSunriseColor = clr(255, 189, 157);
clear.mFogDayColor = clr(206, 227, 255);
clear.mFogSunsetColor = clr(255, 189, 157);
clear.mFogNightColor = clr(9, 10, 11);
clear.mAmbientSunriseColor = clr(47, 66, 96);
clear.mAmbientDayColor = clr(137, 140, 160);
clear.mAmbientSunsetColor = clr(68, 75, 96);
clear.mAmbientNightColor = clr(32, 35, 42);
clear.mSunSunriseColor = clr(242, 159, 99);
clear.mSunDayColor = clr(255, 252, 238);
clear.mSunSunsetColor = clr(255, 115, 79);
clear.mSunNightColor = clr(59, 97, 176);
clear.mSunDiscSunsetColor = clr(255, 189, 157);
clear.mLandFogDayDepth = 0.69;
clear.mLandFogNightDepth = 0.69;
clear.mWindSpeed = 0.1;
clear.mCloudSpeed = 1.25;
clear.mGlareView = 1.0;
mWeatherSettings["clear"] = clear;
Weather cloudy;
cloudy.mCloudTexture = "tx_sky_cloudy.dds";
cloudy.mCloudsMaximumPercent = 1.0;
cloudy.mTransitionDelta = 0.015;
cloudy.mSkySunriseColor = clr(126, 158, 173);
cloudy.mSkyDayColor = clr(117, 160, 215);
cloudy.mSkySunsetColor = clr(111, 114, 159);
cloudy.mSkyNightColor = clr(9, 10, 11);
cloudy.mFogSunriseColor = clr(255, 207, 149);
cloudy.mFogDayColor = clr(245, 235, 224);
cloudy.mFogSunsetColor = clr(255, 155, 106);
cloudy.mFogNightColor = clr(9, 10, 11);
cloudy.mAmbientSunriseColor = clr(66, 74, 87);
cloudy.mAmbientDayColor = clr(137, 145, 160);
cloudy.mAmbientSunsetColor = clr(71, 80, 92);
cloudy.mAmbientNightColor = clr(32, 39, 54);
cloudy.mSunSunriseColor = clr(241, 177, 99);
cloudy.mSunDayColor = clr(255, 236, 221);
cloudy.mSunSunsetColor = clr(255, 89, 00);
cloudy.mSunNightColor = clr(77, 91, 124);
cloudy.mSunDiscSunsetColor = clr(255, 202, 179);
cloudy.mLandFogDayDepth = 0.72;
cloudy.mLandFogNightDepth = 0.72;
cloudy.mWindSpeed = 0.2;
cloudy.mCloudSpeed = 2;
cloudy.mGlareView = 1.0;
mWeatherSettings["cloudy"] = cloudy;
Weather foggy;
foggy.mCloudTexture = "tx_sky_foggy.dds";
foggy.mCloudsMaximumPercent = 1.0;
foggy.mTransitionDelta = 0.015;
foggy.mSkySunriseColor = clr(197, 190, 180);
foggy.mSkyDayColor = clr(184, 211, 228);
foggy.mSkySunsetColor = clr(142, 159, 176);
foggy.mSkyNightColor = clr(18, 23, 28);
foggy.mFogSunriseColor = clr(173, 164, 148);
foggy.mFogDayColor = clr(150, 187, 209);
foggy.mFogSunsetColor = clr(113, 135, 157);
foggy.mFogNightColor = clr(19, 24, 29);
foggy.mAmbientSunriseColor = clr(48, 43, 37);
foggy.mAmbientDayColor = clr(92, 109, 120);
foggy.mAmbientSunsetColor = clr(28, 33, 39);
foggy.mAmbientNightColor = clr(28, 33, 39);
foggy.mSunSunriseColor = clr(177, 162, 137);
foggy.mSunDayColor = clr(111, 131, 151);
foggy.mSunSunsetColor = clr(125, 157, 189);
foggy.mSunNightColor = clr(81, 100, 119);
foggy.mSunDiscSunsetColor = clr(223, 223, 223);
foggy.mLandFogDayDepth = 1.0;
foggy.mLandFogNightDepth = 1.9;
foggy.mWindSpeed = 0;
foggy.mCloudSpeed = 1.25;
foggy.mGlareView = 0.25;
mWeatherSettings["foggy"] = foggy;
Weather thunderstorm;
thunderstorm.mCloudTexture = "tx_sky_thunder.dds";
thunderstorm.mCloudsMaximumPercent = 0.66;
thunderstorm.mTransitionDelta = 0.03;
thunderstorm.mSkySunriseColor = clr(35, 36, 39);
thunderstorm.mSkyDayColor = clr(97, 104, 115);
thunderstorm.mSkySunsetColor = clr(35, 36, 39);
thunderstorm.mSkyNightColor = clr(19, 20, 22);
thunderstorm.mFogSunriseColor = clr(70, 74, 85);
thunderstorm.mFogDayColor = clr(97, 104, 115);
thunderstorm.mFogSunsetColor = clr(70, 74, 85);
thunderstorm.mFogNightColor = clr(19, 20, 22);
thunderstorm.mAmbientSunriseColor = clr(54, 54, 54);
thunderstorm.mAmbientDayColor = clr(90, 90, 90);
thunderstorm.mAmbientSunsetColor = clr(54, 54, 54);
thunderstorm.mAmbientNightColor = clr(49, 51, 54);
thunderstorm.mSunSunriseColor = clr(91, 99, 122);
thunderstorm.mSunDayColor = clr(138, 144, 155);
thunderstorm.mSunSunsetColor = clr(96, 101, 117);
thunderstorm.mSunNightColor = clr(55, 76, 110);
thunderstorm.mSunDiscSunsetColor = clr(128, 128, 128);
thunderstorm.mLandFogDayDepth = 1;
thunderstorm.mLandFogNightDepth = 1.15;
thunderstorm.mWindSpeed = 0.5;
thunderstorm.mCloudSpeed = 3;
thunderstorm.mGlareView = 0;
thunderstorm.mRainLoopSoundID = "rain heavy";
mWeatherSettings["thunderstorm"] = thunderstorm;
Weather rain;
rain.mCloudTexture = "tx_sky_rainy.dds";
rain.mCloudsMaximumPercent = 0.66;
rain.mTransitionDelta = 0.015;
rain.mSkySunriseColor = clr(71, 74, 75);
rain.mSkyDayColor = clr(116, 120, 122);
rain.mSkySunsetColor = clr(73, 73, 73);
rain.mSkyNightColor = clr(24, 25, 26);
rain.mFogSunriseColor = clr(71, 74, 75);
rain.mFogDayColor = clr(116, 120, 122);
rain.mFogSunsetColor = clr(73, 73, 73);
rain.mFogNightColor = clr(24, 25, 26);
rain.mAmbientSunriseColor = clr(97, 90, 88);
rain.mAmbientDayColor = clr(105, 110, 113);
rain.mAmbientSunsetColor = clr(88, 97, 97);
rain.mAmbientNightColor = clr(50, 55, 67);
rain.mSunSunriseColor = clr(131, 122, 120);
rain.mSunDayColor = clr(149, 157, 170);
rain.mSunSunsetColor = clr(120, 126, 131);
rain.mSunNightColor = clr(50, 62, 101);
rain.mSunDiscSunsetColor = clr(128, 128, 128);
rain.mLandFogDayDepth = 0.8;
rain.mLandFogNightDepth = 0.8;
rain.mWindSpeed = 0.3;
rain.mCloudSpeed = 2;
rain.mGlareView = 0;
rain.mRainLoopSoundID = "rain";
mWeatherSettings["rain"] = rain;
Weather overcast;
overcast.mCloudTexture = "tx_sky_overcast.dds";
overcast.mCloudsMaximumPercent = 1.0;
overcast.mTransitionDelta = 0.015;
overcast.mSkySunriseColor = clr(91, 99, 106);
overcast.mSkyDayColor = clr(143, 146, 149);
overcast.mSkySunsetColor = clr(108, 115, 121);
overcast.mSkyNightColor = clr(19, 22, 25);
overcast.mFogSunriseColor = clr(91, 99, 106);
overcast.mFogDayColor = clr(143, 146, 149);
overcast.mFogSunsetColor = clr(108, 115, 121);
overcast.mFogNightColor = clr(19, 22, 25);
overcast.mAmbientSunriseColor = clr(84, 88, 92);
overcast.mAmbientDayColor = clr(93, 96, 105);
overcast.mAmbientSunsetColor = clr(83, 77, 75);
overcast.mAmbientNightColor = clr(57, 60, 66);
overcast.mSunSunriseColor = clr(87, 125, 163);
overcast.mSunDayColor = clr(163, 169, 183);
overcast.mSunSunsetColor = clr(85, 103, 157);
overcast.mSunNightColor = clr(32, 54, 100);
overcast.mSunDiscSunsetColor = clr(128, 128, 128);
overcast.mLandFogDayDepth = 0.7;
overcast.mLandFogNightDepth = 0.7;
overcast.mWindSpeed = 0.2;
overcast.mCloudSpeed = 1.5;
overcast.mGlareView = 0;
mWeatherSettings["overcast"] = overcast;
Weather ashstorm;
ashstorm.mCloudTexture = "tx_sky_ashstorm.dds";
ashstorm.mCloudsMaximumPercent = 1.0;
ashstorm.mTransitionDelta = 0.035;
ashstorm.mSkySunriseColor = clr(91, 56, 51);
ashstorm.mSkyDayColor = clr(124, 73, 58);
ashstorm.mSkySunsetColor = clr(106, 55, 40);
ashstorm.mSkyNightColor = clr(20, 21, 22);
ashstorm.mFogSunriseColor = clr(91, 56, 51);
ashstorm.mFogDayColor = clr(124, 73, 58);
ashstorm.mFogSunsetColor = clr(106, 55, 40);
ashstorm.mFogNightColor = clr(20, 21, 22);
ashstorm.mAmbientSunriseColor = clr(52, 42, 37);
ashstorm.mAmbientDayColor = clr(75, 49, 41);
ashstorm.mAmbientSunsetColor = clr(48, 39, 35);
ashstorm.mAmbientNightColor = clr(36, 42, 49);
ashstorm.mSunSunriseColor = clr(184, 91, 71);
ashstorm.mSunDayColor = clr(228, 139, 114);
ashstorm.mSunSunsetColor = clr(185, 86, 57);
ashstorm.mSunNightColor = clr(54, 66, 74);
ashstorm.mSunDiscSunsetColor = clr(128, 128, 128);
ashstorm.mLandFogDayDepth = 1.1;
ashstorm.mLandFogNightDepth = 1.2;
ashstorm.mWindSpeed = 0.8;
ashstorm.mCloudSpeed = 7;
ashstorm.mGlareView = 0;
ashstorm.mAmbientLoopSoundID = "ashstorm";
mWeatherSettings["ashstorm"] = ashstorm;
Weather blight;
blight.mCloudTexture = "tx_sky_blight.dds";
blight.mCloudsMaximumPercent = 1.0;
blight.mTransitionDelta = 0.04;
blight.mSkySunriseColor = clr(90, 35, 35);
blight.mSkyDayColor = clr(90, 35, 35);
blight.mSkySunsetColor = clr(92, 33, 33);
blight.mSkyNightColor = clr(44, 14, 14);
blight.mFogSunriseColor = clr(90, 35, 35);
blight.mFogDayColor = clr(128, 19, 19);
blight.mFogSunsetColor = clr(92, 33, 33);
blight.mFogNightColor = clr(44, 14, 14);
blight.mAmbientSunriseColor = clr(61, 40, 40);
blight.mAmbientDayColor = clr(79, 54, 54);
blight.mAmbientSunsetColor = clr(61, 40, 40);
blight.mAmbientNightColor = clr(56, 58, 62);
blight.mSunSunriseColor = clr(180, 78, 78);
blight.mSunDayColor = clr(224, 84, 84);
blight.mSunSunsetColor = clr(180, 78, 78);
blight.mSunNightColor = clr(61, 91, 143);
blight.mSunDiscSunsetColor = clr(128, 128, 128);
blight.mLandFogDayDepth = 1.1;
blight.mLandFogNightDepth = 1.2;
blight.mWindSpeed = 0.9;
blight.mCloudSpeed = 9;
blight.mGlareView = 0;
blight.mAmbientLoopSoundID = "blight";
mWeatherSettings["blight"] = blight;
Weather snow;
snow.mCloudTexture = "tx_bm_sky_snow.dds";
snow.mCloudsMaximumPercent = 1.0;
snow.mTransitionDelta = 0.014;
snow.mSkySunriseColor = clr(196, 91, 91);
snow.mSkyDayColor = clr(153, 158, 166);
snow.mSkySunsetColor = clr(96, 115, 134);
snow.mSkyNightColor = clr(31, 35, 39);
snow.mFogSunriseColor = clr(106, 91, 91);
snow.mFogDayColor = clr(153, 158, 166);
snow.mFogSunsetColor = clr(96, 115, 134);
snow.mFogNightColor = clr(31, 35, 39);
snow.mAmbientSunriseColor = clr(92, 84, 84);
snow.mAmbientDayColor = clr(93, 96, 105);
snow.mAmbientSunsetColor = clr(70, 79, 87);
snow.mAmbientNightColor = clr(49, 58, 68);
snow.mSunSunriseColor = clr(141, 109, 109);
snow.mSunDayColor = clr(163, 169, 183);
snow.mSunSunsetColor = clr(101, 121, 141);
snow.mSunNightColor = clr(55, 66, 77);
snow.mSunDiscSunsetColor = clr(128, 128, 128);
snow.mLandFogDayDepth = 1.0;
snow.mLandFogNightDepth = 1.2;
snow.mWindSpeed = 0;
snow.mCloudSpeed = 1.5;
snow.mGlareView = 0;
mWeatherSettings["snow"] = snow;
Weather blizzard;
blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds";
blizzard.mCloudsMaximumPercent = 1.0;
blizzard.mTransitionDelta = 0.030;
blizzard.mSkySunriseColor = clr(91, 99, 106);
blizzard.mSkyDayColor = clr(121, 133, 145);
blizzard.mSkySunsetColor = clr(108, 115, 121);
blizzard.mSkyNightColor = clr(27, 29, 31);
blizzard.mFogSunriseColor = clr(91, 99, 106);
blizzard.mFogDayColor = clr(121, 133, 145);
blizzard.mFogSunsetColor = clr(108, 115, 121);
blizzard.mFogNightColor = clr(21, 24, 28);
blizzard.mAmbientSunriseColor = clr(84, 88, 92);
blizzard.mAmbientDayColor = clr(93, 96, 105);
blizzard.mAmbientSunsetColor = clr(83, 77, 75);
blizzard.mAmbientNightColor = clr(53, 62, 70);
blizzard.mSunSunriseColor = clr(114, 128, 146);
blizzard.mSunDayColor = clr(163, 169, 183);
blizzard.mSunSunsetColor = clr(106, 114, 136);
blizzard.mSunNightColor = clr(57, 66, 74);
blizzard.mSunDiscSunsetColor = clr(128, 128, 128);
blizzard.mLandFogDayDepth = 2.8;
blizzard.mLandFogNightDepth = 3.0;
blizzard.mWindSpeed = 0.9;
blizzard.mCloudSpeed = 7.5;
blizzard.mGlareView = 0;
blizzard.mAmbientLoopSoundID = "BM Blizzard";
mWeatherSettings["blizzard"] = blizzard;
}
void WeatherManager::setWeather(const String& weather, bool instant)
{
if (instant || mFirstUpdate)
{
mNextWeather = "";
mCurrentWeather = weather;
mFirstUpdate = false;
}
else
{
if (mNextWeather != "")
{
// transition more than 50% finished?
if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60) <= 0.5)
mCurrentWeather = mNextWeather;
}
mNextWeather = weather;
mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60;
}
}
WeatherResult WeatherManager::getResult(const String& weather)
{
const Weather& current = mWeatherSettings[weather];
WeatherResult result;
result.mCloudTexture = current.mCloudTexture;
result.mCloudBlendFactor = 0;
result.mCloudOpacity = current.mCloudsMaximumPercent;
result.mWindSpeed = current.mWindSpeed;
result.mCloudSpeed = current.mCloudSpeed;
result.mGlareView = current.mGlareView;
result.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
result.mSunColor = current.mSunDiscSunsetColor;
const float fade_duration = current.mTransitionDelta * 24.f;
result.mNight = (mHour < 6.f+fade_duration || mHour > 20.f-fade_duration);
result.mFogDepth = result.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth;
// night
if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration)
|| mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration))
{
result.mFogColor = current.mFogNightColor;
result.mAmbientColor = current.mAmbientNightColor;
result.mSunColor = current.mSunNightColor;
result.mSkyColor = current.mSkyNightColor;
result.mNightFade = 1.f;
}
// sunrise
else if (mHour >= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) && mHour <= WeatherGlobals::mSunriseTime)
{
if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration))
{
// fade in
float advance = (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)-mHour;
float factor = (advance / fade_duration);
result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor);
result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor);
result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor);
result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor);
result.mNightFade = factor;
}
else if (mHour >= (WeatherGlobals::mSunriseTime-fade_duration))
{
// fade out
float advance = mHour-(WeatherGlobals::mSunriseTime-fade_duration);
float factor = advance / fade_duration;
result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor);
result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor);
result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor);
result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor);
}
else
{
result.mFogColor = current.mFogSunriseColor;
result.mAmbientColor = current.mAmbientSunriseColor;
result.mSunColor = current.mSunSunriseColor;
result.mSkyColor = current.mSkySunriseColor;
}
}
// day
else if (mHour >= (WeatherGlobals::mSunriseTime) && mHour <= (WeatherGlobals::mSunsetTime))
{
result.mFogColor = current.mFogDayColor;
result.mAmbientColor = current.mAmbientDayColor;
result.mSunColor = current.mSunDayColor;
result.mSkyColor = current.mSkyDayColor;
}
// sunset
else if (mHour >= (WeatherGlobals::mSunsetTime) && mHour <= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration))
{
if (mHour <= (WeatherGlobals::mSunsetTime+fade_duration))
{
// fade in
float advance = (WeatherGlobals::mSunsetTime+fade_duration)-mHour;
float factor = (advance / fade_duration);
result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor);
result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor);
result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor);
result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor);
}
else if (mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration))
{
// fade out
float advance = mHour-(WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration);
float factor = advance / fade_duration;
result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor);
result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor);
result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor);
result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor);
result.mNightFade = factor;
}
else
{
result.mFogColor = current.mFogSunsetColor;
result.mAmbientColor = current.mAmbientSunsetColor;
result.mSunColor = current.mSunSunsetColor;
result.mSkyColor = current.mSkySunsetColor;
}
}
return result;
}
WeatherResult WeatherManager::transition(float factor)
{
const WeatherResult& current = getResult(mCurrentWeather);
const WeatherResult& other = getResult(mNextWeather);
WeatherResult result;
result.mCloudTexture = current.mCloudTexture;
result.mNextCloudTexture = other.mCloudTexture;
result.mCloudBlendFactor = factor;
result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity);
result.mFogColor = lerp(current.mFogColor, other.mFogColor);
result.mSunColor = lerp(current.mSunColor, other.mSunColor);
result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor);
result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor);
result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor);
result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth);
result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed);
result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed);
result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity);
result.mGlareView = lerp(current.mGlareView, other.mGlareView);
result.mNight = current.mNight;
// sound change behaviour:
// if 'other' has a new sound, switch to it after 1/2 of the transition length
if (other.mAmbientLoopSoundID != "")
result.mAmbientLoopSoundID = factor>0.5 ? other.mAmbientLoopSoundID : current.mAmbientLoopSoundID;
// if 'current' has a sound and 'other' does not have a sound, turn off the sound immediately
else if (current.mAmbientLoopSoundID != "")
result.mAmbientLoopSoundID = "";
return result;
}
void WeatherManager::update(float duration)
{
mWeatherUpdateTime -= duration;
if (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior())
{
std::string regionstr = mEnvironment->mWorld->getPlayer().getPlayer().getCell()->cell->region;
boost::algorithm::to_lower(regionstr);
if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion)
{
mCurrentRegion = regionstr;
mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*60.f;
std::string weather;
if (mRegionOverrides.find(regionstr) != mRegionOverrides.end())
weather = mRegionOverrides[regionstr];
else
{
// get weather probabilities for the current region
const ESM::Region *region = mEnvironment->mWorld->getStore().regions.find (regionstr);
float clear = region->data.clear/255.f;
float cloudy = region->data.cloudy/255.f;
float foggy = region->data.foggy/255.f;
float overcast = region->data.overcast/255.f;
float rain = region->data.rain/255.f;
float thunder = region->data.thunder/255.f;
float ash = region->data.ash/255.f;
float blight = region->data.blight/255.f;
float snow = region->data.a/255.f;
float blizzard = region->data.b/255.f;
// re-scale to 100 percent
const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard;
srand(time(NULL));
float random = ((rand()%100)/100.f) * total;
if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear)
weather = "blizzard";
else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear)
weather = "snow";
else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear)
weather = "blight";
else if (random >= thunder+rain+overcast+foggy+cloudy+clear)
weather = "ashstorm";
else if (random >= rain+overcast+foggy+cloudy+clear)
weather = "thunderstorm";
else if (random >= overcast+foggy+cloudy+clear)
weather = "rain";
else if (random >= foggy+cloudy+clear)
weather = "overcast";
else if (random >= cloudy+clear)
weather = "foggy";
else if (random >= clear)
weather = "cloudy";
else
weather = "clear";
}
setWeather(weather, false);
/*
std::cout << "roll result: " << random << std::endl;
std::cout << regionstr << " weather probabilities: " << clear << " " << cloudy << " " << foggy << " "
<< overcast << " " << rain << " " << thunder << " " << ash << " " << blight << " " << snow << " "
<< blizzard << std::endl;
std::cout << "New weather : " << weather << std::endl;
*/
}
WeatherResult result;
if (mNextWeather != "")
{
mRemainingTransitionTime -= duration;
if (mRemainingTransitionTime < 0)
{
mCurrentWeather = mNextWeather;
mNextWeather = "";
}
}
if (mNextWeather != "")
result = transition(1-(mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60)));
else
result = getResult(mCurrentWeather);
mRendering->configureFog(result.mFogDepth, result.mFogColor);
// disable sun during night
if (mHour >= WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration
|| mHour <= WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration)
mRendering->getSkyManager()->sunDisable();
else
{
// during day, calculate sun angle
float height = 1-std::abs(((mHour-13)/7.f));
int facing = mHour > 13.f ? 1 : -1;
Vector3 final(
(1-height)*facing,
(1-height)*facing,
height);
mRendering->setSunDirection(final);
mRendering->getSkyManager()->sunEnable();
}
// moon calculations
float night;
if (mHour >= 14)
night = mHour-14;
else if (mHour <= 10)
night = mHour+10;
else
night = 0;
night /= 20.f;
if (night != 0)
{
float moonHeight = 1-std::abs((night-0.5)*2);
int facing = (mHour > 0.f && mHour<12.f) ? 1 : -1;
Vector3 masser(
(1-moonHeight)*facing,
(1-moonHeight)*facing,
moonHeight);
Vector3 secunda(
(1-moonHeight)*facing*0.8,
(1-moonHeight)*facing*1.25,
moonHeight);
mRendering->getSkyManager()->setMasserDirection(masser);
mRendering->getSkyManager()->setSecundaDirection(secunda);
mRendering->getSkyManager()->masserEnable();
mRendering->getSkyManager()->secundaEnable();
float hour_fade;
if (mHour >= 7.f && mHour <= 14.f)
hour_fade = 1-(mHour-7)/3.f;
else if (mHour >= 14 && mHour <= 15.f)
hour_fade = mHour-14;
else
hour_fade = 1;
float secunda_angle_fade;
float masser_angle_fade;
float angle = moonHeight*90.f;
if (angle >= 30 && angle <= 50)
secunda_angle_fade = (angle-30)/20.f;
else if (angle <30)
secunda_angle_fade = 0.f;
else
secunda_angle_fade = 1.f;
if (angle >= 40 && angle <= 50)
masser_angle_fade = (angle-40)/10.f;
else if (angle <40)
masser_angle_fade = 0.f;
else
masser_angle_fade = 1.f;
masser_angle_fade *= hour_fade;
secunda_angle_fade *= hour_fade;
mRendering->getSkyManager()->setMasserFade(masser_angle_fade);
mRendering->getSkyManager()->setSecundaFade(secunda_angle_fade);
}
else
{
mRendering->getSkyManager()->masserDisable();
mRendering->getSkyManager()->secundaDisable();
}
if (mCurrentWeather == "thunderstorm" && mNextWeather == "")
{
if (mThunderFlash > 0)
{
// play the sound after a delay
mThunderSoundDelay -= duration;
if (mThunderSoundDelay <= 0)
{
// pick a random sound
int sound = rand() % 4;
std::string soundname;
if (sound == 0) soundname = WeatherGlobals::mThunderSoundID0;
else if (sound == 1) soundname = WeatherGlobals::mThunderSoundID1;
else if (sound == 2) soundname = WeatherGlobals::mThunderSoundID2;
else if (sound == 3) soundname = WeatherGlobals::mThunderSoundID3;
mEnvironment->mSoundManager->playSound(soundname, 1.0, 1.0);
mThunderSoundDelay = 1000;
}
mThunderFlash -= duration;
if (mThunderFlash > 0)
mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold );
else
{
srand(time(NULL));
mThunderChanceNeeded = rand() % 100;
mThunderChance = 0;
mRendering->getSkyManager()->setThunder( 0.f );
}
}
else
{
// no thunder active
mThunderChance += duration*4; // chance increases by 4 percent every second
if (mThunderChance >= mThunderChanceNeeded)
{
mThunderFlash = WeatherGlobals::mThunderThreshold;
mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold );
mThunderSoundDelay = WeatherGlobals::mThunderSoundDelay;
}
}
}
else
mRendering->getSkyManager()->setThunder(0.f);
mRendering->setAmbientColour(result.mAmbientColor);
mRendering->sunEnable();
mRendering->setSunColour(result.mSunColor);
mRendering->getSkyManager()->setWeather(result);
}
else
{
mRendering->sunDisable();
mRendering->skyDisable();
mRendering->getSkyManager()->setThunder(0.f);
}
}
void WeatherManager::setHour(const float hour)
{
// accelerate a bit for testing
/*
mHour += 0.005;
if (mHour >= 24.f) mHour = 0.f;
std::cout << "hour " << mHour << std::endl;
*/
mHour = hour;
}
void WeatherManager::setDate(const int day, const int month)
{
mDay = day;
mMonth = month;
}
unsigned int WeatherManager::getWeatherID() const
{
// Source: http://www.uesp.net/wiki/Tes3Mod:GetCurrentWeather
if (mCurrentWeather == "clear")
return 0;
else if (mCurrentWeather == "cloudy")
return 1;
else if (mCurrentWeather == "foggy")
return 2;
else if (mCurrentWeather == "overcast")
return 3;
else if (mCurrentWeather == "rain")
return 4;
else if (mCurrentWeather == "thunder")
return 5;
else if (mCurrentWeather == "ashstorm")
return 6;
else if (mCurrentWeather == "blight")
return 7;
else if (mCurrentWeather == "snow")
return 8;
else if (mCurrentWeather == "blizzard")
return 9;
else
return 0;
}
void WeatherManager::changeWeather(const std::string& region, const unsigned int id)
{
std::string weather;
if (id==0)
weather = "clear";
else if (id==1)
weather = "cloudy";
else if (id==2)
weather = "foggy";
else if (id==3)
weather = "overcast";
else if (id==4)
weather = "rain";
else if (id==5)
weather = "thunder";
else if (id==6)
weather = "ashstorm";
else if (id==7)
weather = "blight";
else if (id==8)
weather = "snow";
else if (id==9)
weather = "blizzard";
else
weather = "clear";
mRegionOverrides[region] = weather;
}

@ -0,0 +1,272 @@
#ifndef GAME_MWWORLD_WEATHER_H
#define GAME_MWWORLD_WEATHER_H
#include <OgreString.h>
#include <OgreColourValue.h>
namespace MWRender
{
class RenderingManager;
}
namespace MWWorld
{
class Environment;
/// Global weather manager properties (according to INI)
struct WeatherGlobals
{
/*
[Weather]
EnvReduceColor=255,255,255,255
LerpCloseColor=037,046,048,255
BumpFadeColor=230,239,255,255
AlphaReduce=0.35
Minimum Time Between Environmental Sounds=1.0
Maximum Time Between Environmental Sounds=5.0
Sun Glare Fader Max=0.5
Sun Glare Fader Angle Max=30.0
Sun Glare Fader Color=222,095,039
Timescale Clouds=0
Precip Gravity=575
Hours Between Weather Changes=20
Rain Ripples=1
Rain Ripple Radius=1024
Rain Ripples Per Drop=1
Rain Ripple Scale=0.3
Rain Ripple Speed=1.0
Fog Depth Change Speed=3
Sunrise Time=6
Sunset Time=18
Sunrise Duration=2
Sunset Duration=2
Sky Pre-Sunrise Time=.5
Sky Post-Sunrise Time=1
Sky Pre-Sunset Time=1.5
Sky Post-Sunset Time=.5
Ambient Pre-Sunrise Time=.5
Ambient Post-Sunrise Time=2
Ambient Pre-Sunset Time=1
Ambient Post-Sunset Time=1.25
Fog Pre-Sunrise Time=.5
Fog Post-Sunrise Time=1
Fog Pre-Sunset Time=2
Fog Post-Sunset Time=1
Sun Pre-Sunrise Time=0
Sun Post-Sunrise Time=0
Sun Pre-Sunset Time=1
Sun Post-Sunset Time=1.25
Stars Post-Sunset Start=1
Stars Pre-Sunrise Finish=2
Stars Fading Duration=2
Snow Ripples=0
Snow Ripple Radius=1024
Snow Ripples Per Flake=1
Snow Ripple Scale=0.3
Snow Ripple Speed=1.0
Snow Gravity Scale=0.1
Snow High Kill=700
Snow Low Kill=150
[Moons]
Masser Size=94
Masser Fade In Start=14
Masser Fade In Finish=15
Masser Fade Out Start=7
Masser Fade Out Finish=10
Masser Axis Offset=35
Masser Speed=.5
Masser Daily Increment=1
Masser Fade Start Angle=50
Masser Fade End Angle=40
Masser Moon Shadow Early Fade Angle=0.5
Secunda Size=40
Secunda Fade In Start=14
Secunda Fade In Finish=15
Secunda Fade Out Start=7
Secunda Fade Out Finish=10
Secunda Axis Offset=50
Secunda Speed=.6
Secunda Daily Increment=1.2
Secunda Fade Start Angle=50
Secunda Fade End Angle=30
Secunda Moon Shadow Early Fade Angle=0.5
Script Color=255,20,20
*/
static const float mSunriseTime = 8;
static const float mSunsetTime = 18;
static const float mSunriseDuration = 2;
static const float mSunsetDuration = 2;
static const float mWeatherUpdateTime = 20.f;
// morrowind sets these per-weather, but since they are only used by 'thunderstorm'
// weather setting anyway, we can just as well set them globally
static const float mThunderFrequency = .4;
static const float mThunderThreshold = 0.6;
static const float mThunderSoundDelay = 0.25;
static const std::string mThunderSoundID0;
static const std::string mThunderSoundID1;
static const std::string mThunderSoundID2;
static const std::string mThunderSoundID3;
};
/// Defines the actual weather that results from weather setting (see below), time of day and weather transition
struct WeatherResult
{
Ogre::String mCloudTexture;
Ogre::String mNextCloudTexture;
float mCloudBlendFactor;
Ogre::ColourValue mFogColor;
Ogre::ColourValue mAmbientColor;
Ogre::ColourValue mSkyColor;
Ogre::ColourValue mSunColor;
Ogre::ColourValue mSunDiscColor;
float mFogDepth;
float mWindSpeed;
float mCloudSpeed;
float mCloudOpacity;
float mGlareView;
bool mNight; // use night skybox
float mNightFade; // fading factor for night skybox
Ogre::String mAmbientLoopSoundID;
};
/// Defines a single weather setting (according to INI)
struct Weather
{
Ogre::String mCloudTexture;
// Sky (atmosphere) colors
Ogre::ColourValue mSkySunriseColor,
mSkyDayColor,
mSkySunsetColor,
mSkyNightColor;
// Fog colors
Ogre::ColourValue mFogSunriseColor,
mFogDayColor,
mFogSunsetColor,
mFogNightColor;
// Ambient lighting colors
Ogre::ColourValue mAmbientSunriseColor,
mAmbientDayColor,
mAmbientSunsetColor,
mAmbientNightColor;
// Sun (directional) lighting colors
Ogre::ColourValue mSunSunriseColor,
mSunDayColor,
mSunSunsetColor,
mSunNightColor;
// Fog depth/density
float mLandFogDayDepth,
mLandFogNightDepth;
// Color modulation for the sun itself during sunset (not completely sure)
Ogre::ColourValue mSunDiscSunsetColor;
// Duration of weather transition (in days)
float mTransitionDelta;
// No idea what this one is used for?
float mWindSpeed;
// Cloud animation speed multiplier
float mCloudSpeed;
// Multiplier for clouds transparency
float mCloudsMaximumPercent;
// Value between 0 and 1, defines the strength of the sun glare effect
float mGlareView;
// Sound effect
// This is used for Blight, Ashstorm and Blizzard (Bloodmoon)
Ogre::String mAmbientLoopSoundID;
// Rain sound effect
Ogre::String mRainLoopSoundID;
/// \todo disease chance
};
///
/// Interface for weather settings
///
class WeatherManager
{
public:
WeatherManager(MWRender::RenderingManager*, MWWorld::Environment*);
/**
* Change the weather in the specified region
* @param region that should be changed
* @param ID of the weather setting to shift to
*/
void changeWeather(const std::string& region, const unsigned int id);
/**
* Per-frame update
* @param duration
*/
void update(float duration);
void setHour(const float hour);
void setDate(const int day, const int month);
unsigned int getWeatherID() const;
private:
float mHour;
int mDay, mMonth;
MWRender::RenderingManager* mRendering;
MWWorld::Environment* mEnvironment;
std::map<Ogre::String, Weather> mWeatherSettings;
std::map<std::string, std::string> mRegionOverrides;
Ogre::String mCurrentWeather;
Ogre::String mNextWeather;
std::string mCurrentRegion;
bool mFirstUpdate;
float mWeatherUpdateTime;
float mRemainingTransitionTime;
float mThunderFlash;
float mThunderChance;
float mThunderChanceNeeded;
float mThunderSoundDelay;
WeatherResult transition(const float factor);
WeatherResult getResult(const Ogre::String& weather);
void setWeather(const Ogre::String& weather, bool instant=false);
};
}
#endif // GAME_MWWORLD_WEATHER_H

@ -13,15 +13,20 @@
#include "../mwsound/soundmanager.hpp"
#include "ptr.hpp"
#include "environment.hpp"
#include "class.hpp"
#include "player.hpp"
#include "weather.hpp"
#include "refdata.hpp"
#include "globals.hpp"
#include "cellfunctors.hpp"
#include <OgreVector3.h>
using namespace Ogre;
namespace
{
template<typename T>
@ -135,12 +140,16 @@ namespace MWWorld
void World::adjustSky()
{
if (mSky)
if (mSky && (isCellExterior() || isCellQuasiExterior()))
{
toggleSky();
// TODO set weather
toggleSky();
mRendering->skySetHour (mGlobalVariables->getFloat ("gamehour"));
mRendering->skySetDate (mGlobalVariables->getInt ("day"),
mGlobalVariables->getInt ("month"));
mRendering->getSkyManager()->enable();
}
else
mRendering->getSkyManager()->disable();
}
World::World (OEngine::Render::OgreRenderer& renderer,
@ -148,13 +157,15 @@ namespace MWWorld
const std::string& master, const boost::filesystem::path& resDir,
bool newGame, Environment& environment, const std::string& encoding)
: mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0),
mSky (false), mEnvironment (environment), mNextDynamicRecord (0), mCells (mStore, mEsm, *this)
mSky (true), mEnvironment (environment), mNextDynamicRecord (0), mCells (mStore, mEsm, *this)
{
mPhysics = new PhysicsSystem(renderer);
mPhysEngine = mPhysics->getEngine();
mRendering = new MWRender::RenderingManager(renderer, resDir, mPhysEngine, environment);
mWeatherManager = new MWWorld::WeatherManager(mRendering, &environment);
boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master));
std::cout << "Loading ESM " << masterPath.string() << "\n";
@ -181,8 +192,10 @@ namespace MWWorld
}
World::~World()
{
delete mWeatherManager;
delete mWorldScene;
delete mGlobalVariables;
delete mRendering;
@ -369,6 +382,8 @@ namespace MWWorld
mRendering->skySetHour (hour);
mWeatherManager->setHour (hour);
if (days>0)
setDay (days + mGlobalVariables->getInt ("day"));
}
@ -403,6 +418,10 @@ namespace MWWorld
mGlobalVariables->setInt ("month", month);
mRendering->skySetDate (day, month);
mWeatherManager->setDate (day, month);
}
void World::setMonth (int month)
@ -437,10 +456,6 @@ namespace MWWorld
else
{
mSky = true;
// TODO check for extorior or interior with sky.
mRendering->skySetHour (mGlobalVariables->getFloat ("gamehour"));
mRendering->skySetDate (mGlobalVariables->getInt ("day"),
mGlobalVariables->getInt ("month"));
mRendering->skyEnable();
return true;
}
@ -610,7 +625,7 @@ namespace MWWorld
bool World::toggleCollisionMode()
{
return mPhysics->toggleCollisionMode();
return mPhysics->toggleCollisionMode();;
}
bool World::toggleRenderMode (RenderMode mode)
@ -687,5 +702,56 @@ namespace MWWorld
void World::update (float duration)
{
mWorldScene->update (duration);
mWeatherManager->update (duration);
// cast a ray from player to sun to detect if the sun is visible
// this is temporary until we find a better place to put this code
// currently its here because we need to access the physics system
float* p = mPlayer->getPlayer().getRefData().getPosition().pos;
Vector3 sun = mRendering->getSkyManager()->getRealSunPos();
sun = Vector3(sun.x, -sun.z, sun.y);
mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun));
}
bool World::isCellExterior() const
{
Ptr::CellStore *currentCell = mWorldScene->getCurrentCell();
if (currentCell)
{
if (!(currentCell->cell->data.flags & ESM::Cell::Interior))
return true;
else
return false;
}
return false;
}
bool World::isCellQuasiExterior() const
{
Ptr::CellStore *currentCell = mWorldScene->getCurrentCell();
if (currentCell)
{
if (!(currentCell->cell->data.flags & ESM::Cell::QuasiEx))
return false;
else
return true;
}
return false;
}
int World::getCurrentWeather() const
{
return mWeatherManager->getWeatherID();
}
void World::changeWeather(const std::string& region, const unsigned int id)
{
mWeatherManager->changeWeather(region, id);
}
OEngine::Render::Fader* World::getFader()
{
return mRendering->getFader();
}
}

@ -20,6 +20,7 @@
#include "localscripts.hpp"
#include <openengine/bullet/physic.hpp>
#include <openengine/ogre/fader.hpp>
namespace Ogre
{
@ -49,6 +50,7 @@ namespace MWRender
namespace MWWorld
{
class WeatherManager;
class Environment;
class Player;
@ -60,13 +62,16 @@ namespace MWWorld
enum RenderMode
{
Render_CollisionDebug
Render_CollisionDebug,
Render_Wireframe
};
private:
MWRender::RenderingManager* mRendering;
MWWorld::WeatherManager* mWeatherManager;
MWWorld::Scene *mWorldScene;
MWWorld::Player *mPlayer;
ESM::ESMReader mEsm;
@ -102,6 +107,8 @@ namespace MWWorld
~World();
OEngine::Render::Fader* getFader();
Ptr::CellStore *getExterior (int x, int y);
Ptr::CellStore *getInterior (const std::string& name);
@ -119,6 +126,9 @@ namespace MWWorld
bool hasCellChanged() const;
///< Has the player moved to a different cell, since the last frame?
bool isCellExterior() const;
bool isCellQuasiExterior() const;
Globals::Data& getGlobalVariable (const std::string& name);
Globals::Data getGlobalVariable (const std::string& name) const;
@ -154,6 +164,10 @@ namespace MWWorld
bool toggleSky();
///< \return Resulting mode
void changeWeather(const std::string& region, const unsigned int id);
int getCurrentWeather() const;
int getMasserPhase() const;
int getSecundaPhase() const;
@ -224,6 +238,7 @@ namespace MWWorld
/// references that are currently not in the rendered scene should be ignored.
void update (float duration);
};
}

@ -33,6 +33,7 @@
#
# For each of these components, the following variables are defined:
#
# OGRE_${COMPONENT}_FOUND - ${COMPONENT} is available
# OGRE_${COMPONENT}_INCLUDE_DIRS - additional include directories for ${COMPONENT}
# OGRE_${COMPONENT}_LIBRARIES - link these to use ${COMPONENT}
@ -539,4 +540,3 @@ set(OGRE_MEDIA_SEARCH_SUFFIX
clear_if_changed(OGRE_PREFIX_WATCH OGRE_MEDIA_DIR)
find_path(OGRE_MEDIA_DIR NAMES packs/cubemapsJS.zip HINTS ${OGRE_MEDIA_SEARCH_PATH}
PATHS ${OGRE_PREFIX_PATH} PATH_SUFFIXES ${OGRE_MEDIA_SEARCH_SUFFIX})

@ -6,10 +6,6 @@ add_component_dir (bsa
bsa_archive bsa_file
)
add_component_dir (cfg
configurationmanager
)
add_component_dir (nif
controlled effect nif_types record controller extra node record_ptr data nif_file property
)
@ -47,7 +43,7 @@ add_component_dir (misc
)
add_component_dir (files
linuxpath windowspath macospath path multidircollection collections fileops
linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager
)
add_component_dir (compiler

@ -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 */

@ -153,7 +153,7 @@ public:
*************************************************************************/
int getVer() { return mCtx.header.version; }
float getFVer() { return *((float*)&mCtx.header.version); }
float getFVer() { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; }
int getSpecial() { return mSpf; }
const std::string getAuthor() { return mCtx.header.author.toString(); }
const std::string getDesc() { return mCtx.header.desc.toString(); }

@ -1,9 +1,11 @@
#ifndef FILE_FINDER_MAIN_H
#define FILE_FINDER_MAIN_H
#include <map>
#include "search.hpp"
#include "filename_less.hpp"
#include <map>
#include <components/files/multidircollection.hpp>
namespace FileFinder
{
@ -11,7 +13,8 @@ namespace FileFinder
template <typename LESS>
class FileFinderT
{
std::map<std::string, std::string, LESS> table;
typedef std::map<std::string, std::string, LESS> TableContainer;
TableContainer table;
struct Inserter : ReturnPath
{
@ -35,12 +38,12 @@ public:
// Remember the original path length, so we can cut it away from
// the relative paths used as keys
std::string pstring = path.string();
const std::string& pstring = path.string();
inserter.cut = pstring.size();
// If the path does not end in a slash, then boost will add one
// later, which means one more character we have to remove.
char last = pstring[pstring.size()-1];
char last = *pstring.rbegin();
if(last != '\\' && last != '/')
inserter.cut++;
@ -56,12 +59,84 @@ public:
// Find the full path from a relative path.
const std::string &lookup(const std::string& file) const
{
return table.find(file)->second;
static std::string empty;
typename TableContainer::const_iterator it = table.find(file);
return (it != table.end()) ? it->second : empty;
}
};
template
<
class LESS
>
struct TreeFileFinder
{
typedef TreeFileFinder<LESS> finder_t;
TreeFileFinder(const Files::PathContainer& paths, bool recurse = true)
{
struct : ReturnPath
{
finder_t *owner;
int cut;
void add(const boost::filesystem::path &pth)
{
std::string file = pth.string();
std::string key = file.substr(cut);
owner->mTable[key] = file;
}
} inserter;
inserter.owner = this;
for (Files::PathContainer::const_iterator it = paths.begin(); it != paths.end(); ++it)
{
// Remember the original path length, so we can cut it away from
// the relative paths used as keys
const std::string& pstring = it->string();
inserter.cut = pstring.size();
// If the path does not end in a slash, then boost will add one
// later, which means one more character we have to remove.
char last = *pstring.rbegin();
if (last != '\\' && last != '/')
{
inserter.cut++;
}
// Fill the map
find(*it, inserter, recurse);
}
}
bool has(const std::string& file) const
{
return mTable.find(file) != mTable.end();
}
const std::string& lookup(const std::string& file) const
{
static std::string empty;
typename TableContainer::const_iterator it = mTable.find(file);
return (it != mTable.end()) ? it->second : empty;
}
private:
typedef std::map<std::string, std::string, LESS> TableContainer;
TableContainer mTable;
// Inserter inserter;
};
// The default is to use path_less for equality checks
typedef FileFinderT<path_less> FileFinder;
typedef FileFinderT<path_slash> FileFinderStrict;
}
#endif
typedef TreeFileFinder<path_less> LessTreeFileFinder;
typedef TreeFileFinder<path_slash> StrictTreeFileFinder;
} /* namespace FileFinder */
#endif /* FILE_FINDER_MAIN_H */

@ -2,27 +2,35 @@
#include <iostream>
using namespace std;
using namespace boost::filesystem;
void FileFinder::find(const path & dir_path, ReturnPath &ret, bool recurse)
void FileFinder::find(const boost::filesystem::path & dir_path, ReturnPath &ret, bool recurse)
{
if ( !exists( dir_path ) )
{
cout << "Path " << dir_path << " not found\n";
return;
}
directory_iterator end_itr; // default construction yields past-the-end
for ( directory_iterator itr(dir_path);
itr != end_itr;
++itr )
if (boost::filesystem::exists(dir_path))
{
if ( is_directory( *itr ) )
if (!recurse)
{
if(recurse) find(*itr, ret);
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
for (boost::filesystem::directory_iterator itr(dir_path); itr != end_itr; ++itr)
{
if (!boost::filesystem::is_directory( *itr ))
{
ret.add(*itr);
}
}
}
else
ret.add(*itr);
else
{
boost::filesystem::recursive_directory_iterator end_itr; // default construction yields past-the-end
for (boost::filesystem::recursive_directory_iterator itr(dir_path); itr != end_itr; ++itr)
{
if (!boost::filesystem::is_directory(*itr))
{
ret.add(*itr);
}
}
}
}
else
{
std::cout << "Path " << dir_path << " not found" << std::endl;
}
}

@ -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,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 */

@ -22,12 +22,13 @@
#include "linuxpath.hpp"
#if defined(__linux__)
#if defined(__linux__) || defined(__FreeBSD__)
#include <cstdlib>
#include <cstring>
#include <pwd.h>
#include <unistd.h>
#include <boost/filesystem/fstream.hpp>
/**
* \namespace Files
@ -35,126 +36,128 @@
namespace Files
{
boost::filesystem::path LinuxPath::getLocalConfigPath() const
boost::filesystem::path LinuxPath::getUserPath() const
{
boost::filesystem::path localConfigPath(".");
boost::filesystem::path userPath(".");
boost::filesystem::path suffix("/");
const char* theDir = getenv("OPENMW_CONFIG");
const char* theDir = getenv("HOME");
if (theDir == NULL)
{
theDir = getenv("XDG_CONFIG_HOME");
if (theDir == NULL)
struct passwd* pwd = getpwuid(getuid());
if (pwd != NULL)
{
theDir = getenv("HOME");
if (theDir == NULL)
{
struct passwd* pwd = getpwuid(getuid());
if (pwd != NULL)
{
theDir = pwd->pw_dir;
}
}
if (theDir != NULL)
{
suffix = boost::filesystem::path("/.config/");
}
theDir = pwd->pw_dir;
}
}
if (theDir != NULL) {
localConfigPath = boost::filesystem::path(theDir);
if (theDir != NULL)
{
suffix = boost::filesystem::path("/.config/");
userPath = boost::filesystem::path(theDir);
}
localConfigPath /= suffix;
userPath /= suffix;
return localConfigPath;
return userPath;
}
boost::filesystem::path LinuxPath::getGlobalConfigPath() const
boost::filesystem::path LinuxPath::getGlobalPath() const
{
boost::filesystem::path globalConfigPath("/etc/xdg/");
char* theDir = getenv("XDG_CONFIG_DIRS");
if (theDir != NULL)
{
// We take only first path from list
char* ptr = strtok(theDir, ":");
if (ptr != NULL)
{
globalConfigPath = boost::filesystem::path(ptr);
globalConfigPath /= boost::filesystem::path("/");
}
}
return globalConfigPath;
boost::filesystem::path globalPath("/etc/");
return globalPath;
}
boost::filesystem::path LinuxPath::getRuntimeConfigPath() const
boost::filesystem::path LinuxPath::getLocalPath() const
{
return boost::filesystem::path("./");
}
boost::filesystem::path LinuxPath::getLocalDataPath() const
boost::filesystem::path LinuxPath::getGlobalDataPath() const
{
boost::filesystem::path localDataPath(".");
boost::filesystem::path suffix("/");
boost::filesystem::path globalDataPath("/usr/share/games/");
return globalDataPath;
}
const char* theDir = getenv("OPENMW_DATA");
if (theDir == NULL)
boost::filesystem::path LinuxPath::getInstallPath() const
{
boost::filesystem::path installPath;
char *homePath = getenv("HOME");
if (homePath == NULL)
{
theDir = getenv("XDG_DATA_HOME");
if (theDir == NULL)
struct passwd* pwd = getpwuid(getuid());
if (pwd != NULL)
{
theDir = getenv("HOME");
if (theDir == NULL)
{
struct passwd* pwd = getpwuid(getuid());
if (pwd != NULL)
{
theDir = pwd->pw_dir;
}
}
if (theDir != NULL)
{
suffix = boost::filesystem::path("/.local/share/");
}
homePath = pwd->pw_dir;
}
}
if (theDir != NULL) {
localDataPath = boost::filesystem::path(theDir);
}
if (homePath != NULL)
{
boost::filesystem::path wineDefaultRegistry(homePath);
wineDefaultRegistry /= ".wine/system.reg";
localDataPath /= suffix;
return localDataPath;
}
if (boost::filesystem::is_regular_file(wineDefaultRegistry))
{
boost::filesystem::ifstream file(wineDefaultRegistry);
bool isRegEntry = false;
std::string line;
std::string mwpath;
boost::filesystem::path LinuxPath::getGlobalDataPath() const
{
boost::filesystem::path globalDataPath("/usr/local/share/");
while (std::getline(file, line))
{
if (line[0] == '[') // we found an entry
{
if (isRegEntry)
{
break;
}
char* theDir = getenv("XDG_DATA_DIRS");
if (theDir != NULL)
{
// We take only first path from list
char* ptr = strtok(theDir, ":");
if (ptr != NULL)
{
globalDataPath = boost::filesystem::path(ptr);
globalDataPath /= boost::filesystem::path("/");
isRegEntry = (line.find("Softworks\\\\Morrowind]") != std::string::npos);
}
else if (isRegEntry)
{
if (line[0] == '"') // empty line means new registry key
{
std::string key = line.substr(1, line.find('"', 1) - 1);
if (strcasecmp(key.c_str(), "Installed Path") == 0)
{
std::string::size_type valuePos = line.find('=') + 2;
mwpath = line.substr(valuePos, line.rfind('"') - valuePos);
std::string::size_type pos = mwpath.find("\\");
while (pos != std::string::npos)
{
mwpath.replace(pos, 2, "/");
pos = mwpath.find("\\", pos + 1);
}
break;
}
}
}
}
if (!mwpath.empty())
{
// Change drive letter to lowercase, so we could use
// ~/.wine/dosdevices symlinks
mwpath[0] = tolower(mwpath[0]);
installPath /= homePath;
installPath /= ".wine/dosdevices/";
installPath /= mwpath;
if (!boost::filesystem::is_directory(installPath))
{
installPath.clear();
}
}
}
}
return globalDataPath;
}
boost::filesystem::path LinuxPath::getRuntimeDataPath() const
{
return boost::filesystem::path("./data/");
return installPath;
}
} /* namespace Files */
#endif /* defined(__linux__) */
#endif /* defined(__linux__) || defined(__FreeBSD__) */

@ -23,7 +23,7 @@
#ifndef COMPONENTS_FILES_LINUXPATH_H
#define COMPONENTS_FILES_LINUXPATH_H
#if defined(__linux__)
#if defined(__linux__) || defined(__FreeBSD__)
#include <boost/filesystem.hpp>
@ -39,18 +39,18 @@ namespace Files
struct LinuxPath
{
/**
* \brief Return path to the local configuration directory.
* \brief Return path to the user directory.
*
* \return boost::filesystem::path
*/
boost::filesystem::path getLocalConfigPath() const;
boost::filesystem::path getUserPath() const;
/**
* \brief Return path to the global (system) configuration directory.
* \brief Return path to the global (system) directory where game files could be placed.
*
* \return boost::filesystem::path
*/
boost::filesystem::path getGlobalConfigPath() const;
boost::filesystem::path getGlobalPath() const;
/**
* \brief Return path to the runtime configuration directory which is the
@ -58,33 +58,25 @@ struct LinuxPath
*
* \return boost::filesystem::path
*/
boost::filesystem::path getRuntimeConfigPath() const;
boost::filesystem::path getLocalPath() const;
/**
* \brief Return path to the local data directory.
*
* \return boost::filesystem::path
*/
boost::filesystem::path getLocalDataPath() const;
/**
* \brief Return path to the global (system) data directory.
* \brief
*
* \return boost::filesystem::path
*/
boost::filesystem::path getGlobalDataPath() const;
/**
* \brief Return runtime data path which is a location where
* an application was started with 'data' suffix.
* \brief Gets the path of the installed Morrowind version if there is one.
*
* \return boost::filesystem::path
*/
boost::filesystem::path getRuntimeDataPath() const;
boost::filesystem::path getInstallPath() const;
};
} /* namespace Files */
#endif /* defined(__linux__) */
#endif /* defined(__linux__) || defined(__FreeBSD__) */
#endif /* COMPONENTS_FILES_LINUXPATH_H */

@ -27,6 +27,11 @@
#include <cstdlib>
#include <pwd.h>
#include <unistd.h>
#include <boost/filesystem/fstream.hpp>
/**
* FIXME: Someone with MacOS system should check this and correct if necessary
*/
/**
* \namespace Files
@ -34,9 +39,9 @@
namespace Files
{
boost::filesystem::path MacOsPath::getLocalConfigPath() const
boost::filesystem::path MacOsPath::getUserPath() const
{
boost::filesystem::path localConfigPath(".");
boost::filesystem::path userPath(".");
boost::filesystem::path suffix("/");
const char* theDir = getenv("HOME");
@ -50,66 +55,107 @@ boost::filesystem::path MacOsPath::getLocalConfigPath() const
}
if (theDir != NULL)
{
localConfigPath = boost::filesystem::path(theDir) / "Library/Preferences/";
userPath = boost::filesystem::path(theDir) / "Library/Preferences/";
}
localConfigPath /= suffix;
userPath /= suffix;
return localConfigPath;
return userPath;
}
boost::filesystem::path MacOsPath::getGlobalConfigPath() const
boost::filesystem::path MacOsPath::getGlobalPath() const
{
boost::filesystem::path globalConfigPath("/Library/Preferences/");
return globalConfigPath;
boost::filesystem::path globalPath("/Library/Preferences/");
return globalPath;
}
boost::filesystem::path MacOsPath::getRuntimeConfigPath() const
boost::filesystem::path MacOsPath::getLocalPath() const
{
return boost::filesystem::path("./");
}
boost::filesystem::path MacOsPath::getLocalDataPath() const
boost::filesystem::path MacOsPath::getGlobalDataPath() const
{
boost::filesystem::path localDataPath(".");
boost::filesystem::path suffix("/");
boost::filesystem::path globalDataPath("/Library/Application Support/");
return globalDataPath;
}
const char* theDir = getenv("OPENMW_DATA");
if (theDir == NULL)
boost::filesystem::path MacOsPath::getInstallPath() const
{
boost::filesystem::path installPath;
char *homePath = getenv("HOME");
if (homePath == NULL)
{
theDir = getenv("HOME");
if (theDir == NULL)
{
struct passwd* pwd = getpwuid(getuid());
if (pwd != NULL)
{
theDir = pwd->pw_dir;
}
}
if (theDir != NULL)
struct passwd* pwd = getpwuid(getuid());
if (pwd != NULL)
{
suffix = boost::filesystem::path("/Library/Application Support/");
homePath = pwd->pw_dir;
}
}
if (theDir != NULL)
if (homePath != NULL)
{
localDataPath = boost::filesystem::path(theDir);
}
boost::filesystem::path wineDefaultRegistry(homePath);
wineDefaultRegistry /= ".wine/system.reg";
localDataPath /= suffix;
return localDataPath;
}
if (boost::filesystem::is_regular_file(wineDefaultRegistry))
{
boost::filesystem::ifstream file(wineDefaultRegistry);
bool isRegEntry = false;
std::string line;
std::string mwpath;
boost::filesystem::path MacOsPath::getGlobalDataPath() const
{
boost::filesystem::path globalDataPath("/Library/Application Support/");
return globalDataPath;
}
while (std::getline(file, line))
{
if (line[0] == '[') // we found an entry
{
if (isRegEntry)
{
break;
}
isRegEntry = (line.find("Softworks\\\\Morrowind]") != std::string::npos);
}
else if (isRegEntry)
{
if (line[0] == '"') // empty line means new registry key
{
std::string key = line.substr(1, line.find('"', 1) - 1);
if (strcasecmp(key.c_str(), "Installed Path") == 0)
{
std::string::size_type valuePos = line.find('=') + 2;
mwpath = line.substr(valuePos, line.rfind('"') - valuePos);
std::string::size_type pos = mwpath.find("\\");
while (pos != std::string::npos)
{
mwpath.replace(pos, 2, "/");
pos = mwpath.find("\\", pos + 1);
}
break;
}
}
}
}
boost::filesystem::path MacOsPath::getRuntimeDataPath() const
{
return boost::filesystem::path("./data/");
if (!mwpath.empty())
{
// Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks
mwpath[0] = tolower(mwpath[0]);
installPath /= homePath;
installPath /= ".wine/dosdevices/";
installPath /= mwpath;
if (!boost::filesystem::is_directory(installPath))
{
installPath.clear();
}
}
}
}
return installPath;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save