forked from teamnwah/openmw-tes3coop
Merge branch 'master' of https://github.com/zinnschlag/openmw.git into DialogueSystem
This commit is contained in:
commit
10321ff51a
283 changed files with 16655 additions and 486 deletions
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -1,6 +0,0 @@
|
||||||
[submodule "libs/mangle"]
|
|
||||||
path = libs/mangle
|
|
||||||
url = git://github.com/zinnschlag/mangle.git
|
|
||||||
[submodule "libs/openengine"]
|
|
||||||
path = libs/openengine
|
|
||||||
url = git://github.com/zinnschlag/OpenEngine
|
|
|
@ -255,6 +255,13 @@ if (APPLE)
|
||||||
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
|
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
|
||||||
|
|
||||||
# prepare plugins
|
# prepare plugins
|
||||||
|
if (${CMAKE_BUILD_TYPE} MATCHES "Release" OR
|
||||||
|
${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo")
|
||||||
|
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
|
||||||
|
else()
|
||||||
|
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
|
||||||
|
endif()
|
||||||
|
|
||||||
foreach(plugin ${USED_OGRE_PLUGINS})
|
foreach(plugin ${USED_OGRE_PLUGINS})
|
||||||
configure_file("${OGRE_PLUGIN_DIR}/${plugin}.dylib"
|
configure_file("${OGRE_PLUGIN_DIR}/${plugin}.dylib"
|
||||||
"${APP_BUNDLE_DIR}/Contents/Plugins/${plugin}.dylib"
|
"${APP_BUNDLE_DIR}/Contents/Plugins/${plugin}.dylib"
|
||||||
|
@ -265,8 +272,7 @@ endif (APPLE)
|
||||||
|
|
||||||
# Compiler settings
|
# Compiler settings
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
if (CMAKE_COMPILER_IS_GNUCC)
|
||||||
#add_definitions (-Wall -Werror)
|
add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-unused-but-set-parameter -Wno-reorder)
|
||||||
add_definitions (-Wall)
|
|
||||||
endif (CMAKE_COMPILER_IS_GNUCC)
|
endif (CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
|
||||||
if(DPKG_PROGRAM)
|
if(DPKG_PROGRAM)
|
||||||
|
@ -343,6 +349,9 @@ if(WIN32)
|
||||||
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
||||||
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
||||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
|
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
|
||||||
|
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico")
|
||||||
|
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico")
|
||||||
|
# SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
||||||
|
|
||||||
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
|
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
|
||||||
if(EXISTS ${VCREDIST32})
|
if(EXISTS ${VCREDIST32})
|
||||||
|
@ -402,6 +411,45 @@ if (WIN32)
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
||||||
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
|
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
||||||
|
|
||||||
|
# Play a bit with the warning levels
|
||||||
|
|
||||||
|
set(WARNINGS "/Wall") # Since windows can only disable specific warnings, not enable them
|
||||||
|
|
||||||
|
set(WARNINGS_DISABLE
|
||||||
|
# Warnings that aren't enabled normally and don't need to be enabled
|
||||||
|
# They're unneeded and sometimes completely retarded warnings that /Wall enables
|
||||||
|
# Not going to bother commenting them as they tend to warn on every standard library files
|
||||||
|
4061 4263 4264 4266 4350 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946
|
||||||
|
|
||||||
|
# Warnings that are thrown on standard libraries and not OpenMW
|
||||||
|
4347 # Non-template function with same name and parameter count as template function
|
||||||
|
4365 # Variable signed/unsigned mismatch
|
||||||
|
4510 4512 # Unable to generate copy constructor/assignment operator as it's not public in the base
|
||||||
|
4706 # Assignment in conditional expression
|
||||||
|
4738 # Storing 32-bit float result in memory, possible loss of performance
|
||||||
|
4986 # Undocumented warning that occurs in the crtdbg.h file
|
||||||
|
4996 # Function was declared deprecated
|
||||||
|
|
||||||
|
# OpenMW specific warnings
|
||||||
|
4099 # Type mismatch, declared class or struct is defined with other type
|
||||||
|
4100 # Unreferenced formal parameter (-Wunused-parameter)
|
||||||
|
4127 # Conditional expression is constant
|
||||||
|
4242 # Storing value in a variable of a smaller type, possible loss of data
|
||||||
|
4244 # Storing value of one type in variable of another (size_t in int, for example)
|
||||||
|
4305 # Truncating value (double to float, for example)
|
||||||
|
4309 # Variable overflow, trying to store 128 in a signed char for example
|
||||||
|
4355 # Using 'this' in member initialization list
|
||||||
|
4701 # Potentially uninitialized local variable used
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(d ${WARNINGS_DISABLE})
|
||||||
|
set(WARNINGS "${WARNINGS} /wd${d}")
|
||||||
|
endforeach(d)
|
||||||
|
|
||||||
|
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||||
|
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||||
|
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||||
endif(MSVC)
|
endif(MSVC)
|
||||||
|
|
||||||
# Same for MinGW
|
# Same for MinGW
|
||||||
|
|
138
README_Mac.md
138
README_Mac.md
|
@ -1,46 +1,30 @@
|
||||||
NOTE: This README is for ardekantur's Mac branch of OpenMW. A README
|
#Getting OpenMW Working on OS X
|
||||||
for the main branch has yet to be written. If you want to submit one,
|
|
||||||
please send me a message!
|
|
||||||
|
|
||||||
OpenMW
|
## Initial setup
|
||||||
======
|
First of all, clone OpenMW repo.
|
||||||
|
|
||||||
From the [official website][]:
|
$ git clone github.com/zinnschlag/openmw
|
||||||
|
|
||||||
> OpenMW is an attempt to reimplement the popular role playing game
|
Or use your github url if you forked.
|
||||||
Morrowind. It aims to be a fully playable, open source
|
|
||||||
implementation of the game. You must own Morrowind to use OpenMW.
|
|
||||||
|
|
||||||
|
About dependencies: I prefer not to install them globally (i. e. in /usr/local/), so I'm installing them in directory in my home directory. If OpenMW sources is in $HOME/path/openmw, I'm using $HOME/path/libs/root as prefix for boost and other libs.
|
||||||
|
|
||||||
About This Project
|
|
||||||
------------------
|
|
||||||
|
|
||||||
This specific repository is a branch of OpenMW intended to keep pace
|
|
||||||
with development of the project in order to provide a Mac build for
|
|
||||||
interested parties to contribute. This is not an official, sanctioned
|
|
||||||
branch of the OpenMW project. I will only be able to answer specific
|
|
||||||
questions about getting this project running on Mac OS X, **no other
|
|
||||||
platform**. I will not even be able to guarantee my changes maintain
|
|
||||||
backwards compatibility against builds in other operating systems. You
|
|
||||||
have been warned.
|
|
||||||
|
|
||||||
|
|
||||||
Getting OpenMW Working
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
1. Clone this repository.
|
|
||||||
2. Note about libs: I prefer not to install them globally (i. e. in /usr/local/), so I installing them in directory in my home directory. If OpenMW sources is in $HOME/path/openmw, I'm using $HOME/path/libs/root as prefix for boost and other libs.
|
|
||||||
It's useful to create env var for lib install prefix:
|
It's useful to create env var for lib install prefix:
|
||||||
$ export OMW_LIB_PREFIX=$HOME/path/libs/root
|
|
||||||
|
|
||||||
3. First of all, set for current terminal some env vars:
|
$ export OMW_LIB_PREFIX=$HOME/path/libs/root`
|
||||||
|
|
||||||
|
Most of libs can be installed from [Homebrew][homebrew]. Only mpg123 needs to be installed from source (due to lack of universal compilation support). I think that some of libs can be installed from MacPorts or Fink too.
|
||||||
|
|
||||||
|
As OpenMW currently only supports i386 architecture on OS X, denendencies also should support it. Set some env vars in current terminal:
|
||||||
|
|
||||||
$ export CFLAGS="-arch i386"
|
$ export CFLAGS="-arch i386"
|
||||||
$ export CXXFLAGS="-arch i386"
|
$ export CXXFLAGS="-arch i386"
|
||||||
$ export LDFLAGS="-arch i386"
|
$ export LDFLAGS="-arch i386"
|
||||||
All libs will build with correct architecture.
|
|
||||||
If you close your terminal, you should set env vars again before pcoceeding to next steps!
|
If you close your terminal, you should set env vars again before pcoceeding to next steps!
|
||||||
|
|
||||||
4. Download [boost][] (tested with 1.45) and install it with the following command:
|
## Boost
|
||||||
|
Download [boost][boost] and install it with the following command:
|
||||||
|
|
||||||
$ cd /path/to/boost/source
|
$ cd /path/to/boost/source
|
||||||
$ ./bootstrap.sh --prefix=$OMW_LIB_PREFIX
|
$ ./bootstrap.sh --prefix=$OMW_LIB_PREFIX
|
||||||
|
@ -49,32 +33,47 @@ Getting OpenMW Working
|
||||||
--link-shared,static --prefix=$OMW_LIB_PREFIX install
|
--link-shared,static --prefix=$OMW_LIB_PREFIX install
|
||||||
|
|
||||||
|
|
||||||
5. Download [Ogre][] SDK (tested with 1.7.2), unpack it and move
|
Alternatively you can install boost with homebrew:
|
||||||
`lib/Release/Ogre.framework` into `Library/Frameworks`.
|
|
||||||
|
|
||||||
6. Download [OIS][] and use the XCode project provided in
|
$ brew install boost --universal
|
||||||
`ois/Mac/XCode-2.2`. Be sure to set your build architecture to
|
|
||||||
`i386` and your SDK platform to either 10.5 or 10.6. Once it
|
I think MacPorts also should support universal build for boost.
|
||||||
builds, move `ois/Mac/XCode-2.2/build/Debug/OIS.framework` to
|
|
||||||
`/Library/Frameworks`.
|
## Ogre
|
||||||
|
Download [Ogre][] SDK (tested with 1.7.3), unpack it somewhere and move
|
||||||
|
`lib/Release/Ogre.framework` into `/Library/Frameworks`.
|
||||||
|
|
||||||
|
## OIS
|
||||||
|
Download patched [OIS][] and use the XCode project provided. Be sure to set your build architecture to
|
||||||
|
`i386`. Once it built, locate built OIS.framework with Xcode and move it to `/Library/Frameworks`.
|
||||||
|
|
||||||
|
## mpg123
|
||||||
|
Download [MPG 123][mpg123] and build it:
|
||||||
|
|
||||||
7. Download [mpg123][] and build it:
|
|
||||||
$ cd /path/to/mpg123/source
|
$ cd /path/to/mpg123/source
|
||||||
$ ./configure --prefix=$OMW_LIB_PREFIX --disable-debug \
|
$ ./configure --prefix=$OMW_LIB_PREFIX --disable-debug \
|
||||||
--disable-dependency-tracking \
|
--disable-dependency-tracking \
|
||||||
--with-optimization=4 \
|
--with-optimization=4 \
|
||||||
--with-audio=coreaudio \
|
--with-audio=dummy \
|
||||||
--with-default-audio=coreaudio \
|
--with-default-audio=dummy \
|
||||||
--with-cpu=sse_alone \
|
--with-cpu=sse_alone \
|
||||||
$ make install
|
$ make install
|
||||||
|
|
||||||
8. Download [libsndfile][] and build it:
|
## libsndfile
|
||||||
|
Download [libsndfile][] and build it:
|
||||||
|
|
||||||
$ cd /path/to/libsndfile/source
|
$ cd /path/to/libsndfile/source
|
||||||
$ ./configure --prefix=$OMW_LIB_PREFIX \
|
$ ./configure --prefix=$OMW_LIB_PREFIX \
|
||||||
--disable-dependency-tracking
|
--disable-dependency-tracking
|
||||||
$ make install
|
$ make install
|
||||||
|
|
||||||
9. Download [Bullet][] and build it:
|
or install with homebrew:
|
||||||
|
|
||||||
|
$ brew install libsndfile --universal
|
||||||
|
|
||||||
|
## Bullet
|
||||||
|
Download [Bullet][] and build it:
|
||||||
|
|
||||||
$ cd /path/to/bullet/source
|
$ cd /path/to/bullet/source
|
||||||
$ mkdir build
|
$ mkdir build
|
||||||
$ cd build
|
$ cd build
|
||||||
|
@ -87,12 +86,25 @@ Getting OpenMW Working
|
||||||
-G"Unix Makefiles" ../
|
-G"Unix Makefiles" ../
|
||||||
$ make install
|
$ make install
|
||||||
|
|
||||||
10. Generate the Makefile for OpenMW as follows and build OpenMW:
|
or install with homebrew:
|
||||||
|
|
||||||
|
$ brew install bullet --HEAD --universal
|
||||||
|
|
||||||
|
I prefer head because 2.79 has some issue which causes OpenMW to lag. Also you can edit formula and install 2.77, which is stable and haven't mentioned issue.
|
||||||
|
|
||||||
|
## Qt
|
||||||
|
Install [Qt][qt]. Qt SDK distributed by Nokia is not an option because it's 64 bit only, and OpenMW currently doesn't build for 64 bit on OS X. I'm installing it from Homebrew:
|
||||||
|
|
||||||
|
$ brew install qt --universal
|
||||||
|
|
||||||
|
## Run CMake
|
||||||
|
Generate the Makefile for OpenMW as follows and build OpenMW:
|
||||||
|
|
||||||
$ mkdir /path/to/openmw/build/dir
|
$ mkdir /path/to/openmw/build/dir
|
||||||
$ cd /path/to/open/build/dir
|
$ cd /path/to/open/build/dir
|
||||||
$ cmake \
|
$ cmake \
|
||||||
-D CMAKE_OSX_ARCHITECTURES=i386 \
|
-D CMAKE_OSX_ARCHITECTURES=i386 \
|
||||||
-D OGRESDK=/path/to/ogre/sdk \
|
-D OGRE_SDK=/path/to/ogre/sdk \
|
||||||
-D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \
|
-D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \
|
||||||
-D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \
|
-D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \
|
||||||
-D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
-D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
||||||
|
@ -106,27 +118,43 @@ Getting OpenMW Working
|
||||||
-D BULLET_INCLUDE_DIR=$OMW_LIB_PREFIX/include/bullet/ \
|
-D BULLET_INCLUDE_DIR=$OMW_LIB_PREFIX/include/bullet/ \
|
||||||
-G "Unix Makefiles" /path/to/openmw/source/dir
|
-G "Unix Makefiles" /path/to/openmw/source/dir
|
||||||
$ make
|
$ make
|
||||||
You can use -G"Xcode" if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles"
|
|
||||||
if you prefer Eclipse. You also can specify -D CMAKE_BUILD_TYPE=Debug for debug
|
|
||||||
build.
|
|
||||||
|
|
||||||
11. Copy your Morrowind `Data Files` directory into the OpenMW build dir
|
You can use `-G"Xcode"` if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles"
|
||||||
with the name `data` or create symlink:
|
if you prefer Eclipse. You also can specify `-D CMAKE_BUILD_TYPE=Debug` for debug
|
||||||
$ ln -s /path/to/morrowind/data/files /path/to/openmw/build/dir/data
|
build. As for CMake 2.8.7 and Xcode 4.3, Xcode generator is broken. Sadly Eclipse CDT also cannot import generated project at least on my machine.
|
||||||
|
|
||||||
|
If all libs installed via homebrew (excluding mpg123), then command would be even simplier:
|
||||||
|
|
||||||
|
$ cmake \
|
||||||
|
-D CMAKE_OSX_ARCHITECTURES="i386" \
|
||||||
|
-D OGRE_SDK=/path/to/ogre/sdk \
|
||||||
|
-D MPG123_LIBRARY=$OMW_LIB_PREFIX/lib/libmpg123.a \
|
||||||
|
-D MPG123_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
||||||
|
-G "Unix Makefiles" /path/to/openmw/source/dir
|
||||||
|
$ make
|
||||||
|
|
||||||
|
Note for users with recent Xcode versions: you must explicitly specify what set of compilers do you use! If not, gcc will be used for C and Clang for C++. Just add this two -D's to command: `-D CMAKE_C_COMPILER=/usr/bin/clang` and `-D CMAKE_CXX_COMPILER=/usr/bin/clang`
|
||||||
|
|
||||||
|
Note for Xcode 4.3 users: you should specify full path to used SDK, because current CMake (2.8.7) couldn't find SDKs inside Xcode app bundle:
|
||||||
|
|
||||||
|
-D CMAKE_OSX_SYSROOT="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk"
|
||||||
|
|
||||||
|
# Run
|
||||||
|
From your build directory run:
|
||||||
|
|
||||||
12. From your build directory run:
|
|
||||||
$ OpenMW.app/Contents/MacOS/openmw
|
$ OpenMW.app/Contents/MacOS/openmw
|
||||||
or:
|
or:
|
||||||
|
|
||||||
$ open OpenMW.app
|
$ open OpenMW.app
|
||||||
Enjoy!
|
Enjoy!
|
||||||
|
|
||||||
|
[homebrew]: https://github.com/mxcl/homebrew
|
||||||
|
|
||||||
[boost]: http://www.boost.org
|
[boost]: http://www.boost.org
|
||||||
[Ogre]: http://www.ogre3d.org
|
[Ogre]: http://www.ogre3d.org
|
||||||
[Bullet]: http://bulletphysics.org
|
[Bullet]: http://bulletphysics.org
|
||||||
[OIS]: http://wgois.sf.net
|
[OIS]: https://github.com/corristo/ois-fork
|
||||||
[mpg123]: http://www.mpg123.de
|
[mpg123]: http://www.mpg123.de
|
||||||
[libsndfile]: http://www.mega-nerd.com/libsndfile
|
[libsndfile]: http://www.mega-nerd.com/libsndfile
|
||||||
[official website]: http://openmw.com
|
[official website]: http://openmw.com
|
||||||
[Will Thimbleby's Ogre Framework]: http://www.thimbleby.net/ogre/
|
[Will Thimbleby's Ogre Framework]: http://www.thimbleby.net/ogre/
|
||||||
|
[qt]: http://qt.nokia.com/
|
|
@ -41,10 +41,11 @@ source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC
|
||||||
find_package(Qt4 REQUIRED)
|
find_package(Qt4 REQUIRED)
|
||||||
set(QT_USE_QTGUI 1)
|
set(QT_USE_QTGUI 1)
|
||||||
|
|
||||||
if (NOT APPLE) # this dependency can be completely removed, but now it only tested on OS X
|
# Set some platform specific settings
|
||||||
find_package(PNG REQUIRED)
|
if(WIN32)
|
||||||
include_directories(${PNG_INCLUDE_DIR})
|
set(GUI_TYPE WIN32)
|
||||||
endif()
|
set(QT_USE_QTMAIN TRUE)
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
QT4_ADD_RESOURCES(RCC_SRCS resources.qrc)
|
QT4_ADD_RESOURCES(RCC_SRCS resources.qrc)
|
||||||
QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
|
QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
|
||||||
|
@ -53,6 +54,7 @@ include(${QT_USE_FILE})
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
add_executable(omwlauncher
|
add_executable(omwlauncher
|
||||||
|
${GUI_TYPE}
|
||||||
${LAUNCHER}
|
${LAUNCHER}
|
||||||
${RCC_SRCS}
|
${RCC_SRCS}
|
||||||
${MOC_SRCS}
|
${MOC_SRCS}
|
||||||
|
@ -62,7 +64,6 @@ target_link_libraries(omwlauncher
|
||||||
${Boost_LIBRARIES}
|
${Boost_LIBRARIES}
|
||||||
${OGRE_LIBRARIES}
|
${OGRE_LIBRARIES}
|
||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
${PNG_LIBRARY}
|
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,23 @@
|
||||||
#include "pluginsmodel.hpp"
|
#include "pluginsmodel.hpp"
|
||||||
#include "pluginsview.hpp"
|
#include "pluginsview.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 ESM;
|
using namespace ESM;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ add_openmw_dir (mwsound
|
||||||
add_openmw_dir (mwworld
|
add_openmw_dir (mwworld
|
||||||
refdata world physicssystem scene environment globals class action nullaction actionteleport
|
refdata world physicssystem scene environment globals class action nullaction actionteleport
|
||||||
containerstore actiontalk actiontake manualref player cellfunctors
|
containerstore actiontalk actiontake manualref player cellfunctors
|
||||||
cells localscripts customdata weather
|
cells localscripts customdata weather inventorystore
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwclass
|
add_openmw_dir (mwclass
|
||||||
|
|
|
@ -118,8 +118,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
||||||
// sound
|
// sound
|
||||||
if (mUseSound)
|
if (mUseSound)
|
||||||
{
|
{
|
||||||
if (!mEnvironment.mSoundManager->isMusicPlaying())
|
mEnvironment.mSoundManager->playPlaylist();
|
||||||
mEnvironment.mSoundManager->startRandomTitle();
|
|
||||||
|
|
||||||
mEnvironment.mSoundManager->update (evt.timeSinceLastFrame);
|
mEnvironment.mSoundManager->update (evt.timeSinceLastFrame);
|
||||||
}
|
}
|
||||||
|
@ -340,7 +339,6 @@ void OMW::Engine::go()
|
||||||
// Create sound system
|
// Create sound system
|
||||||
mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(),
|
mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(),
|
||||||
mOgre->getCamera(),
|
mOgre->getCamera(),
|
||||||
mEnvironment.mWorld->getStore(),
|
|
||||||
mDataDirs,
|
mDataDirs,
|
||||||
mUseSound, mFSStrict, mEnvironment);
|
mUseSound, mFSStrict, mEnvironment);
|
||||||
|
|
||||||
|
@ -389,7 +387,7 @@ void OMW::Engine::go()
|
||||||
mOgre->getRoot()->addFrameListener (this);
|
mOgre->getRoot()->addFrameListener (this);
|
||||||
|
|
||||||
// Play some good 'ol tunes
|
// Play some good 'ol tunes
|
||||||
mEnvironment.mSoundManager->startRandomTitle();
|
mEnvironment.mSoundManager->playPlaylist(std::string("Explore"));
|
||||||
|
|
||||||
// scripts
|
// scripts
|
||||||
if (mCompileAll)
|
if (mCompileAll)
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -53,6 +56,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -71,4 +76,14 @@ namespace MWClass
|
||||||
|
|
||||||
registerClass (typeid (ESM::Apparatus).name(), instance);
|
registerClass (typeid (ESM::Apparatus).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Apparatus::getUpSoundId (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
return std::string("Item Apparatus Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Apparatus::getDownSoundId (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
return std::string("Item Apparatus Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,12 @@ namespace MWClass
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,22 @@
|
||||||
#include "armor.hpp"
|
#include "armor.hpp"
|
||||||
|
|
||||||
#include <components/esm/loadarmo.hpp>
|
#include <components/esm/loadarmo.hpp>
|
||||||
|
#include <components/esm/loadskil.hpp>
|
||||||
|
#include <components/esm/loadgmst.hpp>
|
||||||
|
|
||||||
#include <components/esm_store/cell_store.hpp>
|
#include <components/esm_store/cell_store.hpp>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
#include "../mwworld/world.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -52,6 +60,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -77,10 +87,105 @@ namespace MWClass
|
||||||
return ref->base->script;
|
return ref->base->script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<int>, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Armor, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Armor>();
|
||||||
|
|
||||||
|
std::vector<int> slots;
|
||||||
|
|
||||||
|
const int size = 11;
|
||||||
|
|
||||||
|
static const int sMapping[size][2] =
|
||||||
|
{
|
||||||
|
{ ESM::Armor::Helmet, MWWorld::InventoryStore::Slot_Helmet },
|
||||||
|
{ ESM::Armor::Cuirass, MWWorld::InventoryStore::Slot_Cuirass },
|
||||||
|
{ ESM::Armor::LPauldron, MWWorld::InventoryStore::Slot_LeftPauldron },
|
||||||
|
{ ESM::Armor::RPauldron, MWWorld::InventoryStore::Slot_RightPauldron },
|
||||||
|
{ ESM::Armor::Greaves, MWWorld::InventoryStore::Slot_Greaves },
|
||||||
|
{ ESM::Armor::Boots, MWWorld::InventoryStore::Slot_Boots },
|
||||||
|
{ ESM::Armor::LGauntlet, MWWorld::InventoryStore::Slot_LeftGauntlet },
|
||||||
|
{ ESM::Armor::RGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet },
|
||||||
|
{ ESM::Armor::Shield, MWWorld::InventoryStore::Slot_CarriedLeft },
|
||||||
|
{ ESM::Armor::LBracer, MWWorld::InventoryStore::Slot_LeftGauntlet },
|
||||||
|
{ ESM::Armor::RBracer, MWWorld::InventoryStore::Slot_RightGauntlet }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i=0; i<size; ++i)
|
||||||
|
if (sMapping[i][0]==ref->base->data.type)
|
||||||
|
{
|
||||||
|
slots.push_back (int (sMapping[i][1]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair (slots, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Armor::getEquipmentSkill (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Armor, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Armor>();
|
||||||
|
|
||||||
|
std::string typeGmst;
|
||||||
|
|
||||||
|
switch (ref->base->data.type)
|
||||||
|
{
|
||||||
|
case ESM::Armor::Helmet: typeGmst = "iHelmWeight"; break;
|
||||||
|
case ESM::Armor::Cuirass: typeGmst = "iCuirassWeight"; break;
|
||||||
|
case ESM::Armor::LPauldron:
|
||||||
|
case ESM::Armor::RPauldron: typeGmst = "iPauldronWeight"; break;
|
||||||
|
case ESM::Armor::Greaves: typeGmst = "iGreavesWeight"; break;
|
||||||
|
case ESM::Armor::Boots: typeGmst = "iBootsWeight"; break;
|
||||||
|
case ESM::Armor::LGauntlet:
|
||||||
|
case ESM::Armor::RGauntlet: typeGmst = "iGauntletWeight"; break;
|
||||||
|
/// \todo how to determine if shield light, medium or heavy?
|
||||||
|
// case ESM::Armor::Shield:
|
||||||
|
case ESM::Armor::LBracer:
|
||||||
|
case ESM::Armor::RBracer: typeGmst = "iGauntletWeight"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeGmst.empty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
float iWeight = environment.mWorld->getStore().gameSettings.find (typeGmst)->i;
|
||||||
|
|
||||||
|
if (iWeight * environment.mWorld->getStore().gameSettings.find ("fLightMaxMod")->f>=
|
||||||
|
ref->base->data.weight)
|
||||||
|
return ESM::Skill::LightArmor;
|
||||||
|
|
||||||
|
if (iWeight * environment.mWorld->getStore().gameSettings.find ("fMedMaxMod")->f>=
|
||||||
|
ref->base->data.weight)
|
||||||
|
return ESM::Skill::MediumArmor;
|
||||||
|
|
||||||
|
return ESM::Skill::HeavyArmor;
|
||||||
|
}
|
||||||
|
|
||||||
void Armor::registerSelf()
|
void Armor::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Armor);
|
boost::shared_ptr<Class> instance (new Armor);
|
||||||
|
|
||||||
registerClass (typeid (ESM::Armor).name(), instance);
|
registerClass (typeid (ESM::Armor).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Armor::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
int es = getEquipmentSkill(ptr, environment);
|
||||||
|
if (es == ESM::Skill::LightArmor)
|
||||||
|
return std::string("Item Armor Light Up");
|
||||||
|
else if (es == ESM::Skill::MediumArmor)
|
||||||
|
return std::string("Item Armor Medium Up");
|
||||||
|
else
|
||||||
|
return std::string("Item Armor Heavy Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Armor::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
int es = getEquipmentSkill(ptr, environment);
|
||||||
|
if (es == ESM::Skill::LightArmor)
|
||||||
|
return std::string("Item Armor Light Down");
|
||||||
|
else if (es == ESM::Skill::MediumArmor)
|
||||||
|
return std::string("Item Armor Medium Down");
|
||||||
|
else
|
||||||
|
return std::string("Item Armor Heavy Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,22 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
|
virtual int getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||||
|
const MWWorld::Environment& environment) const;
|
||||||
|
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||||
|
/// no such skill.
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Book::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Book::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -55,6 +58,8 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// TODO implement reading
|
// TODO implement reading
|
||||||
|
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -73,4 +78,14 @@ namespace MWClass
|
||||||
|
|
||||||
registerClass (typeid (ESM::Book).name(), instance);
|
registerClass (typeid (ESM::Book).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Book::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Book Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Book::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Book Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,12 @@ namespace MWClass
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,13 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -53,6 +57,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -65,10 +71,86 @@ namespace MWClass
|
||||||
return ref->base->script;
|
return ref->base->script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<int>, bool> Clothing::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Clothing>();
|
||||||
|
|
||||||
|
std::vector<int> slots;
|
||||||
|
|
||||||
|
if (ref->base->data.type==ESM::Clothing::Ring)
|
||||||
|
{
|
||||||
|
slots.push_back (int (MWWorld::InventoryStore::Slot_LeftRing));
|
||||||
|
slots.push_back (int (MWWorld::InventoryStore::Slot_RightRing));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int size = 9;
|
||||||
|
|
||||||
|
static const int sMapping[size][2] =
|
||||||
|
{
|
||||||
|
{ ESM::Clothing::Shirt, MWWorld::InventoryStore::Slot_Cuirass },
|
||||||
|
{ ESM::Clothing::Belt, MWWorld::InventoryStore::Slot_Belt },
|
||||||
|
{ ESM::Clothing::Robe, MWWorld::InventoryStore::Slot_Robe },
|
||||||
|
{ ESM::Clothing::Pants, MWWorld::InventoryStore::Slot_Pants },
|
||||||
|
{ ESM::Clothing::Shoes, MWWorld::InventoryStore::Slot_Boots },
|
||||||
|
{ ESM::Clothing::LGlove, MWWorld::InventoryStore::Slot_LeftGauntlet },
|
||||||
|
{ ESM::Clothing::RGlove, MWWorld::InventoryStore::Slot_RightGauntlet },
|
||||||
|
{ ESM::Clothing::Skirt, MWWorld::InventoryStore::Slot_Skirt },
|
||||||
|
{ ESM::Clothing::Amulet, MWWorld::InventoryStore::Slot_Amulet }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i=0; i<size; ++i)
|
||||||
|
if (sMapping[i][0]==ref->base->data.type)
|
||||||
|
{
|
||||||
|
slots.push_back (int (sMapping[i][1]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair (slots, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Clothing::getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||||
|
const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Clothing>();
|
||||||
|
|
||||||
|
if (ref->base->data.type==ESM::Clothing::Shoes)
|
||||||
|
return ESM::Skill::Unarmored;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void Clothing::registerSelf()
|
void Clothing::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Clothing);
|
boost::shared_ptr<Class> instance (new Clothing);
|
||||||
|
|
||||||
registerClass (typeid (ESM::Clothing).name(), instance);
|
registerClass (typeid (ESM::Clothing).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Clothing::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Clothing>();
|
||||||
|
|
||||||
|
if (ref->base->data.type == 8)
|
||||||
|
{
|
||||||
|
return std::string("Item Ring Up");
|
||||||
|
}
|
||||||
|
return std::string("Item Clothes Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Clothing::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Clothing>();
|
||||||
|
|
||||||
|
if (ref->base->data.type == 8)
|
||||||
|
{
|
||||||
|
return std::string("Item Ring Down");
|
||||||
|
}
|
||||||
|
return std::string("Item Clothes Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,22 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
|
virtual int getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||||
|
const MWWorld::Environment& environment) const;
|
||||||
|
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||||
|
/// no such skill.
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// TODO check for key
|
// TODO check for key
|
||||||
std::cout << "Locked container" << std::endl;
|
std::cout << "Locked container" << std::endl;
|
||||||
environment.mSoundManager->playSound(lockedSound, 1.0, 1.0);
|
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false);
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -100,7 +100,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// Trap activation goes here
|
// Trap activation goes here
|
||||||
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
||||||
environment.mSoundManager->playSound(trapActivationSound, 1.0, 1.0);
|
environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0, false);
|
||||||
ptr.getCellRef().trap = "";
|
ptr.getCellRef().trap = "";
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace MWClass
|
||||||
// TODO check for key
|
// TODO check for key
|
||||||
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
|
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
|
||||||
std::cout << "Locked!" << std::endl;
|
std::cout << "Locked!" << std::endl;
|
||||||
environment.mSoundManager->playSound(lockedSound, 1.0, 1.0);
|
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false);
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// Trap activation
|
// Trap activation
|
||||||
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
||||||
environment.mSoundManager->playSound(trapActivationSound, 1.0, 1.0);
|
environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0, false);
|
||||||
ptr.getCellRef().trap = "";
|
ptr.getCellRef().trap = "";
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,7 @@ namespace MWClass
|
||||||
if (environment.mWorld->getPlayer().getPlayer()==actor)
|
if (environment.mWorld->getPlayer().getPlayer()==actor)
|
||||||
{
|
{
|
||||||
// the player is using the door
|
// the player is using the door
|
||||||
|
// The reason this is not 3D is that it would get interrupted when you teleport
|
||||||
environment.mSoundManager->playSound(openSound, 1.0, 1.0);
|
environment.mSoundManager->playSound(openSound, 1.0, 1.0);
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTeleportPlayer (ref->ref.destCell, ref->ref.doorDest));
|
new MWWorld::ActionTeleportPlayer (ref->ref.destCell, ref->ref.doorDest));
|
||||||
|
@ -109,7 +110,7 @@ namespace MWClass
|
||||||
// TODO return action for rotating the door
|
// TODO return action for rotating the door
|
||||||
|
|
||||||
// This is a little pointless, but helps with testing
|
// This is a little pointless, but helps with testing
|
||||||
environment.mSoundManager->playSound(openSound, 1.0, 1.0);
|
environment.mSoundManager->playSound3D (ptr, openSound, 1.0, 1.0, false);
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -51,6 +54,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -69,4 +74,14 @@ namespace MWClass
|
||||||
|
|
||||||
registerClass (typeid (ESM::Ingredient).name(), instance);
|
registerClass (typeid (ESM::Ingredient).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Ingredient::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Ingredient Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Ingredient::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Ingredient Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,12 @@ namespace MWClass
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
#include "../mwworld/nullaction.hpp"
|
#include "../mwworld/nullaction.hpp"
|
||||||
#include "../mwworld/environment.hpp"
|
#include "../mwworld/environment.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwsound/soundmanager.hpp"
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
|
@ -82,6 +83,8 @@ namespace MWClass
|
||||||
if (!(ref->base->data.flags & ESM::Light::Carry))
|
if (!(ref->base->data.flags & ESM::Light::Carry))
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
|
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -94,10 +97,33 @@ namespace MWClass
|
||||||
return ref->base->script;
|
return ref->base->script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<int>, bool> Light::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Light>();
|
||||||
|
|
||||||
|
std::vector<int> slots;
|
||||||
|
|
||||||
|
if (ref->base->data.flags & ESM::Light::Carry)
|
||||||
|
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedLeft));
|
||||||
|
|
||||||
|
return std::make_pair (slots, false);
|
||||||
|
}
|
||||||
|
|
||||||
void Light::registerSelf()
|
void Light::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Light);
|
boost::shared_ptr<Class> instance (new Light);
|
||||||
|
|
||||||
registerClass (typeid (ESM::Light).name(), instance);
|
registerClass (typeid (ESM::Light).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Light::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Misc Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Light::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Misc Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,17 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,13 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -54,6 +58,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -66,10 +72,29 @@ namespace MWClass
|
||||||
return ref->base->script;
|
return ref->base->script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<int>, bool> Lockpick::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
std::vector<int> slots;
|
||||||
|
|
||||||
|
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||||
|
|
||||||
|
return std::make_pair (slots, false);
|
||||||
|
}
|
||||||
|
|
||||||
void Lockpick::registerSelf()
|
void Lockpick::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Lockpick);
|
boost::shared_ptr<Class> instance (new Lockpick);
|
||||||
|
|
||||||
registerClass (typeid (ESM::Tool).name(), instance);
|
registerClass (typeid (ESM::Tool).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Lockpick Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Lockpick::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Lockpick Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,17 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -53,6 +56,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -71,4 +76,28 @@ namespace MWClass
|
||||||
|
|
||||||
registerClass (typeid (ESM::Miscellaneous).name(), instance);
|
registerClass (typeid (ESM::Miscellaneous).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Miscellaneous>();
|
||||||
|
|
||||||
|
if (ref->base->name =="Gold")
|
||||||
|
{
|
||||||
|
return std::string("Item Gold Up");
|
||||||
|
}
|
||||||
|
return std::string("Item Misc Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Miscellaneous>();
|
||||||
|
|
||||||
|
if (ref->base->name =="Gold")
|
||||||
|
{
|
||||||
|
return std::string("Item Gold Down");
|
||||||
|
}
|
||||||
|
return std::string("Item Misc Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,12 @@ namespace MWClass
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "../mwworld/actiontalk.hpp"
|
#include "../mwworld/actiontalk.hpp"
|
||||||
#include "../mwworld/environment.hpp"
|
#include "../mwworld/environment.hpp"
|
||||||
#include "../mwworld/world.hpp"
|
#include "../mwworld/world.hpp"
|
||||||
#include "../mwworld/containerstore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/customdata.hpp"
|
#include "../mwworld/customdata.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -29,7 +29,7 @@ namespace
|
||||||
MWMechanics::NpcStats mNpcStats;
|
MWMechanics::NpcStats mNpcStats;
|
||||||
MWMechanics::CreatureStats mCreatureStats;
|
MWMechanics::CreatureStats mCreatureStats;
|
||||||
MWMechanics::Movement mMovement;
|
MWMechanics::Movement mMovement;
|
||||||
MWWorld::ContainerStore mContainerStore;
|
MWWorld::InventoryStore mInventoryStore;
|
||||||
|
|
||||||
virtual MWWorld::CustomData *clone() const;
|
virtual MWWorld::CustomData *clone() const;
|
||||||
};
|
};
|
||||||
|
@ -161,7 +161,15 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
ensureCustomData (ptr);
|
||||||
|
|
||||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::InventoryStore& Npc::getInventoryStore (const MWWorld::Ptr& ptr)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
ensureCustomData (ptr);
|
||||||
|
|
||||||
|
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Npc::getScript (const MWWorld::Ptr& ptr) const
|
std::string Npc::getScript (const MWWorld::Ptr& ptr) const
|
||||||
|
|
|
@ -38,6 +38,9 @@ namespace MWClass
|
||||||
virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const;
|
virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return container store
|
///< Return container store
|
||||||
|
|
||||||
|
virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< Return inventory store
|
||||||
|
|
||||||
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -53,6 +56,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -71,4 +76,14 @@ namespace MWClass
|
||||||
|
|
||||||
registerClass (typeid (ESM::Potion).name(), instance);
|
registerClass (typeid (ESM::Potion).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Potion::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Potion Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Potion::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Potion Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,12 @@ namespace MWClass
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,13 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -53,6 +57,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -65,10 +71,29 @@ namespace MWClass
|
||||||
return ref->base->script;
|
return ref->base->script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<int>, bool> Probe::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
std::vector<int> slots;
|
||||||
|
|
||||||
|
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||||
|
|
||||||
|
return std::make_pair (slots, false);
|
||||||
|
}
|
||||||
|
|
||||||
void Probe::registerSelf()
|
void Probe::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Probe);
|
boost::shared_ptr<Class> instance (new Probe);
|
||||||
|
|
||||||
registerClass (typeid (ESM::Probe).name(), instance);
|
registerClass (typeid (ESM::Probe).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Probe::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Probe Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Probe::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Probe Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,17 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -53,6 +56,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -71,4 +76,14 @@ namespace MWClass
|
||||||
|
|
||||||
registerClass (typeid (ESM::Repair).name(), instance);
|
registerClass (typeid (ESM::Repair).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Repair::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Repair Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Repair::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
return std::string("Item Repair Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,12 @@ namespace MWClass
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,13 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontake.hpp"
|
#include "../mwworld/actiontake.hpp"
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
@ -53,6 +57,8 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
}
|
}
|
||||||
|
@ -78,10 +84,157 @@ namespace MWClass
|
||||||
return ref->base->script;
|
return ref->base->script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<int>, bool> Weapon::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Weapon>();
|
||||||
|
|
||||||
|
std::vector<int> slots;
|
||||||
|
bool stack = false;
|
||||||
|
|
||||||
|
if (ref->base->data.type==ESM::Weapon::Arrow || ref->base->data.type==ESM::Weapon::Bolt)
|
||||||
|
{
|
||||||
|
slots.push_back (int (MWWorld::InventoryStore::Slot_Ammunition));
|
||||||
|
stack = true;
|
||||||
|
}
|
||||||
|
else if (ref->base->data.type==ESM::Weapon::MarksmanThrown)
|
||||||
|
{
|
||||||
|
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||||
|
stack = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||||
|
|
||||||
|
return std::make_pair (slots, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Weapon::getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||||
|
const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Weapon>();
|
||||||
|
|
||||||
|
const int size = 12;
|
||||||
|
|
||||||
|
static const int sMapping[size][2] =
|
||||||
|
{
|
||||||
|
{ ESM::Weapon::ShortBladeOneHand, ESM::Skill::ShortBlade },
|
||||||
|
{ ESM::Weapon::LongBladeOneHand, ESM::Skill::LongBlade },
|
||||||
|
{ ESM::Weapon::LongBladeTwoHand, ESM::Skill::LongBlade },
|
||||||
|
{ ESM::Weapon::BluntOneHand, ESM::Skill::BluntWeapon },
|
||||||
|
{ ESM::Weapon::BluntTwoClose, ESM::Skill::BluntWeapon },
|
||||||
|
{ ESM::Weapon::BluntTwoWide, ESM::Skill::BluntWeapon },
|
||||||
|
{ ESM::Weapon::SpearTwoWide, ESM::Skill::Spear },
|
||||||
|
{ ESM::Weapon::AxeOneHand, ESM::Skill::Axe },
|
||||||
|
{ ESM::Weapon::AxeTwoHand, ESM::Skill::Axe },
|
||||||
|
{ ESM::Weapon::MarksmanBow, ESM::Skill::Marksman },
|
||||||
|
{ ESM::Weapon::MarksmanCrossbow, ESM::Skill::Marksman },
|
||||||
|
{ ESM::Weapon::MarksmanThrown, ESM::Skill::Marksman }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i=0; i<size; ++i)
|
||||||
|
if (sMapping[i][0]==ref->base->data.type)
|
||||||
|
return sMapping[i][1];
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void Weapon::registerSelf()
|
void Weapon::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Weapon);
|
boost::shared_ptr<Class> instance (new Weapon);
|
||||||
|
|
||||||
registerClass (typeid (ESM::Weapon).name(), instance);
|
registerClass (typeid (ESM::Weapon).name(), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Weapon::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Weapon>();
|
||||||
|
|
||||||
|
int type = ref->base->data.type;
|
||||||
|
// Ammo
|
||||||
|
if (type == 12 || type == 13)
|
||||||
|
{
|
||||||
|
return std::string("Item Ammo Up");
|
||||||
|
}
|
||||||
|
// Bow
|
||||||
|
if (type == 9)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Bow Up");
|
||||||
|
}
|
||||||
|
// Crossbow
|
||||||
|
if (type == 10)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Crossbow Up");
|
||||||
|
}
|
||||||
|
// Longblades, One hand and Two
|
||||||
|
if (type == 1 || type == 2)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Longblade Up");
|
||||||
|
}
|
||||||
|
// Shortblade and thrown weapons
|
||||||
|
// thrown weapons may not be entirely correct
|
||||||
|
if (type == 0 || type == 11)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Shortblade Up");
|
||||||
|
}
|
||||||
|
// Spear
|
||||||
|
if (type == 6)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Spear Up");
|
||||||
|
}
|
||||||
|
// Blunts and Axes
|
||||||
|
if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Blunt Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string("Item Misc Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Weapon::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Weapon>();
|
||||||
|
|
||||||
|
int type = ref->base->data.type;
|
||||||
|
// Ammo
|
||||||
|
if (type == 12 || type == 13)
|
||||||
|
{
|
||||||
|
return std::string("Item Ammo Down");
|
||||||
|
}
|
||||||
|
// Bow
|
||||||
|
if (type == 9)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Bow Down");
|
||||||
|
}
|
||||||
|
// Crossbow
|
||||||
|
if (type == 10)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Crossbow Down");
|
||||||
|
}
|
||||||
|
// Longblades, One hand and Two
|
||||||
|
if (type == 1 || type == 2)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Longblade Down");
|
||||||
|
}
|
||||||
|
// Shortblade and thrown weapons
|
||||||
|
// thrown weapons may not be entirely correct
|
||||||
|
if (type == 0 || type == 11)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Shortblade Down");
|
||||||
|
}
|
||||||
|
// Spear
|
||||||
|
if (type == 6)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Spear Down");
|
||||||
|
}
|
||||||
|
// Blunts and Axes
|
||||||
|
if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8)
|
||||||
|
{
|
||||||
|
return std::string("Item Weapon Blunt Down");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string("Item Misc Down");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,22 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
|
virtual int getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||||
|
const MWWorld::Environment& environment) const;
|
||||||
|
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||||
|
/// no such skill.
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the pick up sound Id
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the put down sound Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace MWGui
|
||||||
|
|
||||||
return isGood();
|
return isGood();
|
||||||
}
|
}
|
||||||
catch (const Compiler::SourceException& error)
|
catch (const Compiler::SourceException&)
|
||||||
{
|
{
|
||||||
// error has already been reported via error handler
|
// error has already been reported via error handler
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,6 @@ namespace MWRender{
|
||||||
|
|
||||||
Nif::NiTriShapeCopy& copy = *allshapesiter;
|
Nif::NiTriShapeCopy& copy = *allshapesiter;
|
||||||
std::vector<Ogre::Vector3>* allvertices = ©.vertices;
|
std::vector<Ogre::Vector3>* allvertices = ©.vertices;
|
||||||
std::vector<Ogre::Vector3>* allnormals = ©.normals;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,7 +181,6 @@ namespace MWRender{
|
||||||
std::vector<Nif::NiSkinData::IndividualWeight> inds = iter->second;
|
std::vector<Nif::NiSkinData::IndividualWeight> inds = iter->second;
|
||||||
int verIndex = iter->first;
|
int verIndex = iter->first;
|
||||||
Ogre::Vector3 currentVertex = (*allvertices)[verIndex];
|
Ogre::Vector3 currentVertex = (*allvertices)[verIndex];
|
||||||
Ogre::Vector3 currentNormal = (*allnormals)[verIndex];
|
|
||||||
Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]);
|
Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]);
|
||||||
Ogre::Bone *bonePtr = 0;
|
Ogre::Bone *bonePtr = 0;
|
||||||
|
|
||||||
|
@ -276,6 +274,7 @@ namespace MWRender{
|
||||||
rotmult = bonePtr->getOrientation();
|
rotmult = bonePtr->getOrientation();
|
||||||
scale = bonePtr->getScale().x;
|
scale = bonePtr->getScale().x;
|
||||||
boneSequenceIter++;
|
boneSequenceIter++;
|
||||||
|
|
||||||
for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++)
|
for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++)
|
||||||
{
|
{
|
||||||
if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){
|
if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){
|
||||||
|
@ -330,7 +329,7 @@ namespace MWRender{
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
bool Animation::timeIndex( float time, std::vector<float> times, int & i, int & j, float & x ){
|
bool Animation::timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x ){
|
||||||
int count;
|
int count;
|
||||||
if ( (count = times.size()) > 0 )
|
if ( (count = times.size()) > 0 )
|
||||||
{
|
{
|
||||||
|
@ -388,6 +387,8 @@ namespace MWRender{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::handleAnimationTransforms(){
|
void Animation::handleAnimationTransforms(){
|
||||||
|
|
||||||
|
|
||||||
Ogre::SkeletonInstance* skel = base->getSkeleton();
|
Ogre::SkeletonInstance* skel = base->getSkeleton();
|
||||||
|
|
||||||
|
|
||||||
|
@ -404,10 +405,10 @@ namespace MWRender{
|
||||||
for(unsigned int i = 0; i < entityparts.size(); i++){
|
for(unsigned int i = 0; i < entityparts.size(); i++){
|
||||||
//Ogre::SkeletonInstance* skel = entityparts[i]->getSkeleton();
|
//Ogre::SkeletonInstance* skel = entityparts[i]->getSkeleton();
|
||||||
|
|
||||||
Ogre::Bone* b = skel->getRootBone();
|
//Ogre::Bone* b = skel->getRootBone();
|
||||||
b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3));//This is a trick
|
//b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3));//This is a trick
|
||||||
|
|
||||||
entityparts[i]->getAllAnimationStates()->_notifyDirty();
|
//entityparts[i]->getAllAnimationStates()->_notifyDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -424,18 +425,19 @@ namespace MWRender{
|
||||||
float x;
|
float x;
|
||||||
float x2;
|
float x2;
|
||||||
|
|
||||||
std::vector<Ogre::Quaternion> quats = iter->getQuat();
|
const std::vector<Ogre::Quaternion> & quats = iter->getQuat();
|
||||||
|
|
||||||
std::vector<float> ttime = iter->gettTime();
|
const std::vector<float> & ttime = iter->gettTime();
|
||||||
std::vector<float>::iterator ttimeiter = ttime.begin();
|
|
||||||
|
|
||||||
|
const std::vector<float> & rtime = iter->getrTime();
|
||||||
|
int rindexJ = rindexI[slot];
|
||||||
|
|
||||||
std::vector<float> rtime = iter->getrTime();
|
|
||||||
int rindexJ = 0;
|
|
||||||
timeIndex(time, rtime, rindexI[slot], rindexJ, x2);
|
timeIndex(time, rtime, rindexI[slot], rindexJ, x2);
|
||||||
int tindexJ = 0;
|
int tindexJ = tindexI[slot];
|
||||||
|
|
||||||
|
|
||||||
std::vector<Ogre::Vector3> translist1 = iter->getTranslist1();
|
const std::vector<Ogre::Vector3> & translist1 = iter->getTranslist1();
|
||||||
|
|
||||||
timeIndex(time, ttime, tindexI[slot], tindexJ, x);
|
timeIndex(time, ttime, tindexI[slot], tindexJ, x);
|
||||||
|
|
||||||
|
@ -443,34 +445,35 @@ namespace MWRender{
|
||||||
Ogre::Quaternion r;
|
Ogre::Quaternion r;
|
||||||
|
|
||||||
bool bTrans = translist1.size() > 0;
|
bool bTrans = translist1.size() > 0;
|
||||||
|
|
||||||
|
|
||||||
|
bool bQuats = quats.size() > 0;
|
||||||
|
|
||||||
|
if(skel->hasBone(iter->getBonename())){
|
||||||
|
Ogre::Bone* bone = skel->getBone(iter->getBonename());
|
||||||
if(bTrans){
|
if(bTrans){
|
||||||
Ogre::Vector3 v1 = translist1[tindexI[slot]];
|
Ogre::Vector3 v1 = translist1[tindexI[slot]];
|
||||||
Ogre::Vector3 v2 = translist1[tindexJ];
|
Ogre::Vector3 v2 = translist1[tindexJ];
|
||||||
t = (v1 + (v2 - v1) * x);
|
t = (v1 + (v2 - v1) * x);
|
||||||
|
bone->setPosition(t);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bQuats = quats.size() > 0;
|
|
||||||
if(bQuats){
|
if(bQuats){
|
||||||
r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true);
|
r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true);
|
||||||
}
|
|
||||||
skel = base->getSkeleton();
|
|
||||||
if(skel->hasBone(iter->getBonename())){
|
|
||||||
Ogre::Bone* bone = skel->getBone(iter->getBonename());
|
|
||||||
if(bTrans)
|
|
||||||
bone->setPosition(t);
|
|
||||||
if(bQuats)
|
|
||||||
bone->setOrientation(r);
|
bone->setOrientation(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
skel->_updateTransforms();
|
|
||||||
base->getAllAnimationStates()->_notifyDirty();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
slot++;
|
slot++;
|
||||||
}
|
}
|
||||||
|
skel->_updateTransforms();
|
||||||
|
base->getAllAnimationStates()->_notifyDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ class Animation{
|
||||||
static std::map<std::string, int> mUniqueIDs;
|
static std::map<std::string, int> mUniqueIDs;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::vector<Nif::NiTriShapeCopy>* > shapeparts; //All the NiTriShape data that we need for animating an npc
|
std::vector<std::vector<Nif::NiTriShapeCopy>* > shapeparts; //All the NiTriShape data that we need for animating an npc
|
||||||
|
|
||||||
float time;
|
float time;
|
||||||
|
@ -55,7 +56,7 @@ class Animation{
|
||||||
Ogre::Entity* base;
|
Ogre::Entity* base;
|
||||||
void handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel);
|
void handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel);
|
||||||
void handleAnimationTransforms();
|
void handleAnimationTransforms();
|
||||||
bool timeIndex( float time, std::vector<float> times, int & i, int & j, float & x );
|
bool timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x );
|
||||||
std::string getUniqueID(std::string mesh);
|
std::string getUniqueID(std::string mesh);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -65,7 +66,7 @@ class Animation{
|
||||||
void stopScript();
|
void stopScript();
|
||||||
|
|
||||||
|
|
||||||
~Animation();
|
virtual ~Animation();
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace MWRender{
|
||||||
class CreatureAnimation: public Animation{
|
class CreatureAnimation: public Animation{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~CreatureAnimation();
|
virtual ~CreatureAnimation();
|
||||||
CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
||||||
virtual void runAnimation(float timepassed);
|
virtual void runAnimation(float timepassed);
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
|
||||||
std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
|
std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
|
||||||
char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2);
|
char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2);
|
||||||
bool female = tolower(secondtolast) == 'f';
|
bool female = tolower(secondtolast) == 'f';
|
||||||
|
std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower);
|
||||||
bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_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 ;
|
/*std::cout << "Race: " << ref->base->race ;
|
||||||
|
@ -276,6 +277,7 @@ void NpcAnimation::runAnimation(float timepassed){
|
||||||
shapepartsiter++;
|
shapepartsiter++;
|
||||||
entitypartsiter++;
|
entitypartsiter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ class NpcAnimation: public Animation{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
||||||
~NpcAnimation();
|
virtual ~NpcAnimation();
|
||||||
Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename);
|
Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename);
|
||||||
void insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert);
|
void insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert);
|
||||||
virtual void runAnimation(float timepassed);
|
virtual void runAnimation(float timepassed);
|
||||||
|
|
|
@ -210,8 +210,13 @@ void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
|
||||||
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
|
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
|
||||||
{
|
{
|
||||||
/// \todo make the viewing distance and fog start/end configurable
|
/// \todo make the viewing distance and fog start/end configurable
|
||||||
float low = 3000 / density;
|
|
||||||
float high = 6200 / density;
|
// right now we load 3x3 cells, so the maximum viewing distance we
|
||||||
|
// can allow (to prevent objects suddenly popping up) equals:
|
||||||
|
// 8192 * 0.69
|
||||||
|
// ^ cell size ^ minimum density value used (clear weather)
|
||||||
|
float low = 5652.48 / density / 2.f;
|
||||||
|
float high = 5652.48 / density;
|
||||||
|
|
||||||
mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high);
|
mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high);
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,8 @@ void BillboardObject::setPosition(const Vector3& pPosition)
|
||||||
|
|
||||||
Vector3 BillboardObject::getPosition() const
|
Vector3 BillboardObject::getPosition() const
|
||||||
{
|
{
|
||||||
return mNode->getPosition();
|
Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition();
|
||||||
|
return Vector3(p.x, -p.z, p.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BillboardObject::setColour(const ColourValue& pColour)
|
void BillboardObject::setColour(const ColourValue& pColour)
|
||||||
|
@ -161,14 +162,20 @@ Moon::Moon( const String& textureName,
|
||||||
" in float2 uv : TEXCOORD0, \n"
|
" in float2 uv : TEXCOORD0, \n"
|
||||||
" out float4 oColor : COLOR, \n"
|
" out float4 oColor : COLOR, \n"
|
||||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||||
|
" uniform float4 skyColour, \n"
|
||||||
" uniform float4 diffuse, \n"
|
" uniform float4 diffuse, \n"
|
||||||
" uniform float4 emissive \n"
|
" uniform float4 emissive \n"
|
||||||
") \n"
|
") \n"
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" float4 tex = tex2D(texture, uv); \n"
|
" float4 tex = tex2D(texture, uv); \n"
|
||||||
" oColor = float4(emissive.xyz,1) * tex2D(texture, uv) * float4(1,1,1,diffuse.a); \n"
|
" oColor = float4(emissive.xyz,1) * tex; \n"
|
||||||
" float bump = pow((1-diffuse.a),4); \n"
|
// use a circle for the alpha (compute UV distance to center)
|
||||||
" oColor.rgb += float3(bump, bump, bump)*0.5; \n"
|
// looks a bit bad because its not filtered on the edges,
|
||||||
|
// but it's cheaper than a seperate alpha texture.
|
||||||
|
" float sqrUVdist = pow(uv.x-0.5,2) + pow(uv.y-0.5, 2); \n"
|
||||||
|
" oColor.a = diffuse.a * (sqrUVdist >= 0.24 ? 0 : 1); \n"
|
||||||
|
" oColor.rgb += (1-tex.a) * oColor.a * skyColour.rgb; \n"//fill dark side of moon with skycolour
|
||||||
|
" oColor.rgb += (1-diffuse.a) * skyColour.rgb; \n"//fade bump
|
||||||
"}";
|
"}";
|
||||||
fshader->setSource(outStream2.str());
|
fshader->setSource(outStream2.str());
|
||||||
fshader->load();
|
fshader->load();
|
||||||
|
@ -186,10 +193,14 @@ void Moon::setType(const Moon::Type& type)
|
||||||
mType = type;
|
mType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Moon::setSkyColour(const Ogre::ColourValue& colour)
|
||||||
|
{
|
||||||
|
mMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("skyColour", colour);
|
||||||
|
}
|
||||||
|
|
||||||
/// \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)
|
void Moon::setPhase(const Moon::Phase& phase)
|
||||||
{
|
{
|
||||||
|
// Colour texture
|
||||||
Ogre::String textureName = "textures\\tx_";
|
Ogre::String textureName = "textures\\tx_";
|
||||||
|
|
||||||
if (mType == Moon::Type_Secunda) textureName += "secunda_";
|
if (mType == Moon::Type_Secunda) textureName += "secunda_";
|
||||||
|
@ -338,24 +349,11 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) :
|
||||||
mAtmosphereNight = mRootNode->createChildSceneNode();
|
mAtmosphereNight = mRootNode->createChildSceneNode();
|
||||||
mAtmosphereNight->attachObject(night1_ent);
|
mAtmosphereNight->attachObject(night1_ent);
|
||||||
|
|
||||||
for (unsigned int i=0; i<night1_ent->getNumSubEntities(); ++i)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stars vertex shader
|
// Stars vertex shader
|
||||||
HighLevelGpuProgramPtr vshader3 = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
HighLevelGpuProgramPtr stars_vp = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
"cg", GPT_VERTEX_PROGRAM);
|
"cg", GPT_VERTEX_PROGRAM);
|
||||||
vshader3->setParameter("profiles", "vs_2_x arbvp1");
|
stars_vp->setParameter("profiles", "vs_2_x arbvp1");
|
||||||
vshader3->setParameter("entry_point", "main_vp");
|
stars_vp->setParameter("entry_point", "main_vp");
|
||||||
StringUtil::StrStreamType outStream4;
|
StringUtil::StrStreamType outStream4;
|
||||||
outStream4 <<
|
outStream4 <<
|
||||||
"void main_vp( \n"
|
"void main_vp( \n"
|
||||||
|
@ -371,10 +369,9 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) :
|
||||||
" oFade = (position.z > 50) ? 1.f : 0.f; \n"
|
" oFade = (position.z > 50) ? 1.f : 0.f; \n"
|
||||||
" oPosition = mul( worldViewProj, position ); \n"
|
" oPosition = mul( worldViewProj, position ); \n"
|
||||||
"}";
|
"}";
|
||||||
vshader3->setSource(outStream4.str());
|
stars_vp->setSource(outStream4.str());
|
||||||
vshader3->load();
|
stars_vp->load();
|
||||||
vshader3->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
stars_vp->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||||
night1_ent->getSubEntity(3)->getMaterial()->getTechnique(0)->getPass(0)->setVertexProgram(vshader3->getName());
|
|
||||||
|
|
||||||
// Stars fragment shader
|
// Stars fragment shader
|
||||||
HighLevelGpuProgramPtr stars_fp = mgr.createProgram("Stars_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
HighLevelGpuProgramPtr stars_fp = mgr.createProgram("Stars_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
|
@ -399,7 +396,20 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) :
|
||||||
stars_fp->load();
|
stars_fp->load();
|
||||||
stars_fp->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
stars_fp->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||||
stars_fp->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
stars_fp->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
||||||
night1_ent->getSubEntity(3)->getMaterial()->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName());
|
|
||||||
|
for (unsigned int i=0; i<night1_ent->getNumSubEntities(); ++i)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
mp->getTechnique(0)->getPass(0)->setVertexProgram(stars_vp->getName());
|
||||||
|
mp->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName());
|
||||||
|
mStarsMaterials[i] = mp;
|
||||||
|
}
|
||||||
|
|
||||||
// Atmosphere (day)
|
// Atmosphere (day)
|
||||||
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
|
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
|
||||||
|
@ -583,6 +593,9 @@ void SkyManager::update(float duration)
|
||||||
mSun->setVisible(mSunEnabled);
|
mSun->setVisible(mSunEnabled);
|
||||||
mMasser->setVisible(mMasserEnabled);
|
mMasser->setVisible(mMasserEnabled);
|
||||||
mSecunda->setVisible(mSecundaEnabled);
|
mSecunda->setVisible(mSecundaEnabled);
|
||||||
|
|
||||||
|
// rotate the whole sky by 360 degrees every 4 days
|
||||||
|
mRootNode->roll(Degree(mHourDiff*360/96.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::enable()
|
void SkyManager::enable()
|
||||||
|
@ -647,6 +660,8 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
||||||
if (mSkyColour != weather.mSkyColor)
|
if (mSkyColour != weather.mSkyColor)
|
||||||
{
|
{
|
||||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(weather.mSkyColor);
|
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(weather.mSkyColor);
|
||||||
|
mMasser->setSkyColour(weather.mSkyColor);
|
||||||
|
mSecunda->setSkyColour(weather.mSkyColor);
|
||||||
mSkyColour = weather.mSkyColor;
|
mSkyColour = weather.mSkyColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -760,6 +775,9 @@ void SkyManager::setSecundaFade(const float fade)
|
||||||
|
|
||||||
void SkyManager::setHour(double hour)
|
void SkyManager::setHour(double hour)
|
||||||
{
|
{
|
||||||
|
mHourDiff = mHour - hour;
|
||||||
|
if (mHourDiff > 0) mHourDiff -= 24;
|
||||||
|
|
||||||
mHour = hour;
|
mHour = hour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ namespace MWRender
|
||||||
);
|
);
|
||||||
BillboardObject();
|
BillboardObject();
|
||||||
|
|
||||||
|
virtual ~BillboardObject() {}
|
||||||
|
|
||||||
void setColour(const Ogre::ColourValue& pColour);
|
void setColour(const Ogre::ColourValue& pColour);
|
||||||
void setPosition(const Ogre::Vector3& pPosition);
|
void setPosition(const Ogre::Vector3& pPosition);
|
||||||
void setVisible(const bool visible);
|
void setVisible(const bool visible);
|
||||||
|
@ -70,6 +72,8 @@ namespace MWRender
|
||||||
Ogre::SceneNode* rootNode
|
Ogre::SceneNode* rootNode
|
||||||
);
|
);
|
||||||
|
|
||||||
|
virtual ~Moon() {}
|
||||||
|
|
||||||
enum Phase
|
enum Phase
|
||||||
{
|
{
|
||||||
Phase_New = 0,
|
Phase_New = 0,
|
||||||
|
@ -90,6 +94,7 @@ namespace MWRender
|
||||||
|
|
||||||
void setPhase(const Phase& phase);
|
void setPhase(const Phase& phase);
|
||||||
void setType(const Type& type);
|
void setType(const Type& type);
|
||||||
|
void setSkyColour(const Ogre::ColourValue& colour);
|
||||||
|
|
||||||
Phase getPhase() const;
|
Phase getPhase() const;
|
||||||
unsigned int getPhaseInt() const;
|
unsigned int getPhaseInt() const;
|
||||||
|
@ -163,6 +168,8 @@ namespace MWRender
|
||||||
int mDay;
|
int mDay;
|
||||||
int mMonth;
|
int mMonth;
|
||||||
|
|
||||||
|
float mHourDiff;
|
||||||
|
|
||||||
BillboardObject* mSun;
|
BillboardObject* mSun;
|
||||||
BillboardObject* mSunGlare;
|
BillboardObject* mSunGlare;
|
||||||
Moon* mMasser;
|
Moon* mMasser;
|
||||||
|
|
|
@ -10,10 +10,8 @@
|
||||||
#include <mangle/sound/clients/ogre_listener_mover.hpp>
|
#include <mangle/sound/clients/ogre_listener_mover.hpp>
|
||||||
#include <mangle/sound/clients/ogre_output_updater.hpp>
|
#include <mangle/sound/clients/ogre_output_updater.hpp>
|
||||||
|
|
||||||
#include <components/file_finder/file_finder.hpp>
|
|
||||||
#include <components/esm_store/store.hpp>
|
#include <components/esm_store/store.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include "../mwworld/environment.hpp"
|
#include "../mwworld/environment.hpp"
|
||||||
#include "../mwworld/world.hpp"
|
#include "../mwworld/world.hpp"
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
|
@ -45,7 +43,6 @@
|
||||||
|
|
||||||
using namespace Mangle::Sound;
|
using namespace Mangle::Sound;
|
||||||
typedef OEngine::Sound::SoundManager OEManager;
|
typedef OEngine::Sound::SoundManager OEManager;
|
||||||
typedef OEngine::Sound::SoundManagerPtr OEManagerPtr;
|
|
||||||
|
|
||||||
// Set the position on a sound based on a Ptr.
|
// Set the position on a sound based on a Ptr.
|
||||||
static void setPos(SoundPtr &snd, const MWWorld::Ptr ref)
|
static void setPos(SoundPtr &snd, const MWWorld::Ptr ref)
|
||||||
|
@ -60,54 +57,41 @@ static void setPos(SoundPtr &snd, const MWWorld::Ptr ref)
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
struct SoundManager::SoundImpl
|
|
||||||
{
|
|
||||||
/* This is the sound manager. It loades, stores and deletes
|
|
||||||
sounds based on the sound factory it is given.
|
|
||||||
*/
|
|
||||||
OEManagerPtr mgr;
|
|
||||||
SoundPtr music;
|
|
||||||
|
|
||||||
/* This class calls update() on the sound manager each frame
|
SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera,
|
||||||
using and Ogre::FrameListener
|
const Files::PathContainer& dataDirs,
|
||||||
*/
|
bool useSound, bool fsstrict, MWWorld::Environment& environment)
|
||||||
Mangle::Sound::OgreOutputUpdater updater;
|
: mFSStrict(fsstrict)
|
||||||
|
, mEnvironment(environment)
|
||||||
/* This class tracks the movement of an Ogre::Camera and moves
|
, mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY)))
|
||||||
a sound listener automatically to follow it.
|
|
||||||
*/
|
|
||||||
Mangle::Sound::OgreListenerMover cameraTracker;
|
|
||||||
|
|
||||||
const ESMS::ESMStore &store;
|
|
||||||
|
|
||||||
typedef std::map<std::string,Mangle::Sound::WSoundPtr> IDMap;
|
|
||||||
typedef std::map<MWWorld::Ptr,IDMap> PtrMap;
|
|
||||||
PtrMap sounds;
|
|
||||||
|
|
||||||
// This is used for case insensitive and slash-type agnostic file
|
|
||||||
// finding. It takes DOS paths (any case, \\ slashes or / slashes)
|
|
||||||
// relative to the sound dir, and translates them into full paths
|
|
||||||
// of existing files in the filesystem, if they exist.
|
|
||||||
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)
|
, updater(mgr)
|
||||||
, cameraTracker(mgr)
|
, cameraTracker(mgr)
|
||||||
, store(str)
|
, mCurrentPlaylist(NULL)
|
||||||
, FSstrict(fsstrict)
|
|
||||||
, files(soundDir)
|
|
||||||
, strict(soundDir)
|
|
||||||
, musicpath(musicDir)
|
|
||||||
, musicpathStrict(musicDir)
|
|
||||||
{
|
{
|
||||||
|
if(useSound)
|
||||||
|
{
|
||||||
|
// The music library will accept these filetypes
|
||||||
|
// If none is given then it will accept all filetypes
|
||||||
|
std::vector<std::string> acceptableExtensions;
|
||||||
|
acceptableExtensions.push_back(".mp3");
|
||||||
|
acceptableExtensions.push_back(".wav");
|
||||||
|
acceptableExtensions.push_back(".ogg");
|
||||||
|
acceptableExtensions.push_back(".flac");
|
||||||
|
|
||||||
|
// Makes a list of all sound files, searches in reverse for priority reasons
|
||||||
|
for (Files::PathContainer::const_reverse_iterator it = dataDirs.rbegin(); it != dataDirs.rend(); ++it)
|
||||||
|
{
|
||||||
|
Files::FileLister(*it / std::string("Sound"), mSoundFiles, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes a FileLibrary of all music files, searches in reverse for priority reasons
|
||||||
|
for (Files::PathContainer::const_reverse_iterator it = dataDirs.rbegin(); it != dataDirs.rend(); ++it)
|
||||||
|
{
|
||||||
|
mMusicLibrary.add(*it / std::string("Music"), true, mFSStrict, acceptableExtensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string anything = "anything"; // anything is better that a segfault
|
||||||
|
mCurrentPlaylist = mMusicLibrary.section(anything, mFSStrict); // now points to an empty path
|
||||||
|
|
||||||
std::cout << "Sound output: " << SOUND_OUT << std::endl;
|
std::cout << "Sound output: " << SOUND_OUT << std::endl;
|
||||||
std::cout << "Sound decoder: " << SOUND_IN << std::endl;
|
std::cout << "Sound decoder: " << SOUND_IN << std::endl;
|
||||||
|
@ -117,118 +101,21 @@ namespace MWSound
|
||||||
// Tell Ogre to update the sound system each frame
|
// Tell Ogre to update the sound system each frame
|
||||||
root->addFrameListener(&updater);
|
root->addFrameListener(&updater);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~SoundImpl()
|
SoundManager::~SoundManager()
|
||||||
{
|
{
|
||||||
Ogre::Root::getSingleton().removeFrameListener(&updater);
|
Ogre::Root::getSingleton().removeFrameListener(&updater);
|
||||||
cameraTracker.unfollowCamera();
|
cameraTracker.unfollowCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static std::string toMp3(std::string str)
|
|
||||||
{
|
|
||||||
std::string::size_type i = str.rfind('.');
|
|
||||||
if(str.find('/', i) == std::string::npos &&
|
|
||||||
str.find('\\', i) == std::string::npos)
|
|
||||||
str = str.substr(0, i) + ".mp3";
|
|
||||||
else
|
|
||||||
str += ".mp3";
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasFile(const std::string &str, bool music = false)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
if(!FSstrict)
|
|
||||||
{
|
|
||||||
if(music)
|
|
||||||
{
|
|
||||||
found = musicpath.has(str);
|
|
||||||
// Not found? Try with .mp3
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
found = musicpath.has(toMp3(str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
found = files.has(str);
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
found = files.has(toMp3(str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(music)
|
|
||||||
{
|
|
||||||
found = musicpathStrict.has(str);
|
|
||||||
// Not found? Try with .mp3
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
found = musicpathStrict.has(toMp3(str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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
|
|
||||||
// with proper slash conversion (eg. datadir/Sound/Fx/funny.wav)
|
|
||||||
std::string convertPath(const std::string &str, bool music = false)
|
|
||||||
{
|
|
||||||
if(FSstrict == false)
|
|
||||||
{
|
|
||||||
// Search and return
|
|
||||||
if(music && musicpath.has(str))
|
|
||||||
return musicpath.lookup(str);
|
|
||||||
else if(files.has(str))
|
|
||||||
return files.lookup(str);
|
|
||||||
|
|
||||||
// Try mp3 if the wav wasn't found
|
|
||||||
std::string mp3 = toMp3(str);
|
|
||||||
if(music && musicpath.has(mp3))
|
|
||||||
return musicpath.lookup(mp3);
|
|
||||||
else if(files.has(mp3))
|
|
||||||
return files.lookup(mp3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(music && musicpathStrict.has(str))
|
|
||||||
return musicpathStrict.lookup(str);
|
|
||||||
else if(strict.has(str))
|
|
||||||
return strict.lookup(str);
|
|
||||||
|
|
||||||
// Try mp3 if the wav wasn't found
|
|
||||||
std::string mp3 = toMp3(str);
|
|
||||||
if(music && musicpathStrict.has(mp3))
|
|
||||||
return musicpathStrict.lookup(mp3);
|
|
||||||
else if(strict.has(str))
|
|
||||||
return strict.lookup(mp3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give up
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a soundId to file name, and modify the volume
|
// Convert a soundId to file name, and modify the volume
|
||||||
// according to the sounds local volume setting, minRange and
|
// according to the sounds local volume setting, minRange and
|
||||||
// maxRange.
|
// maxRange.
|
||||||
std::string lookup(const std::string &soundId,
|
std::string SoundManager::lookup(const std::string &soundId,
|
||||||
float &volume, float &min, float &max)
|
float &volume, float &min, float &max)
|
||||||
{
|
{
|
||||||
const ESM::Sound *snd = store.sounds.search(soundId);
|
const ESM::Sound *snd = mEnvironment.mWorld->getStore().sounds.search(soundId);
|
||||||
if(snd == NULL) return "";
|
if(snd == NULL) return "";
|
||||||
|
|
||||||
if(snd->data.volume == 0)
|
if(snd->data.volume == 0)
|
||||||
|
@ -249,16 +136,16 @@ namespace MWSound
|
||||||
max = std::max(min, max);
|
max = std::max(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertPath(snd->sound);
|
return Files::FileListLocator(mSoundFiles, snd->sound, mFSStrict, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a sound to the list and play it
|
// Add a sound to the list and play it
|
||||||
void add(const std::string &file,
|
void SoundManager::add(const std::string &file,
|
||||||
MWWorld::Ptr ptr,
|
MWWorld::Ptr ptr,
|
||||||
const std::string &id,
|
const std::string &id,
|
||||||
float volume, float pitch,
|
float volume, float pitch,
|
||||||
float min, float max,
|
float min, float max,
|
||||||
bool loop)
|
bool loop, bool untracked)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -270,8 +157,11 @@ namespace MWSound
|
||||||
setPos(snd, ptr);
|
setPos(snd, ptr);
|
||||||
snd->play();
|
snd->play();
|
||||||
|
|
||||||
|
if (!untracked)
|
||||||
|
{
|
||||||
sounds[ptr][id] = WSoundPtr(snd);
|
sounds[ptr][id] = WSoundPtr(snd);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
std::cout << "Error loading " << file << ", skipping.\n";
|
std::cout << "Error loading " << file << ", skipping.\n";
|
||||||
|
@ -280,7 +170,7 @@ namespace MWSound
|
||||||
|
|
||||||
// Clears all the sub-elements of a given iterator, and then
|
// Clears all the sub-elements of a given iterator, and then
|
||||||
// removes it from 'sounds'.
|
// removes it from 'sounds'.
|
||||||
void clearAll(PtrMap::iterator& it)
|
void SoundManager::clearAll(PtrMap::iterator& it)
|
||||||
{
|
{
|
||||||
IDMap::iterator sit = it->second.begin();
|
IDMap::iterator sit = it->second.begin();
|
||||||
|
|
||||||
|
@ -301,7 +191,7 @@ namespace MWSound
|
||||||
|
|
||||||
// Stop a sound and remove it from the list. If id="" then
|
// Stop a sound and remove it from the list. If id="" then
|
||||||
// remove the entire object and stop all its sounds.
|
// remove the entire object and stop all its sounds.
|
||||||
void remove(MWWorld::Ptr ptr, const std::string &id = "")
|
void SoundManager::remove(MWWorld::Ptr ptr, const std::string &id)
|
||||||
{
|
{
|
||||||
PtrMap::iterator it = sounds.find(ptr);
|
PtrMap::iterator it = sounds.find(ptr);
|
||||||
if(it != sounds.end())
|
if(it != sounds.end())
|
||||||
|
@ -324,7 +214,7 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const
|
bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const
|
||||||
{
|
{
|
||||||
PtrMap::const_iterator it = sounds.find(ptr);
|
PtrMap::const_iterator it = sounds.find(ptr);
|
||||||
if(it != sounds.end())
|
if(it != sounds.end())
|
||||||
|
@ -348,7 +238,7 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all references to objects belonging to a given cell
|
// Remove all references to objects belonging to a given cell
|
||||||
void removeCell(const MWWorld::Ptr::CellStore *cell)
|
void SoundManager::removeCell(const MWWorld::Ptr::CellStore *cell)
|
||||||
{
|
{
|
||||||
PtrMap::iterator it2, it = sounds.begin();
|
PtrMap::iterator it2, it = sounds.begin();
|
||||||
while(it != sounds.end())
|
while(it != sounds.end())
|
||||||
|
@ -360,7 +250,7 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatePositions(MWWorld::Ptr ptr)
|
void SoundManager::updatePositions(MWWorld::Ptr ptr)
|
||||||
{
|
{
|
||||||
// Find the reference (if any)
|
// Find the reference (if any)
|
||||||
PtrMap::iterator it = sounds.find(ptr);
|
PtrMap::iterator it = sounds.find(ptr);
|
||||||
|
@ -378,85 +268,45 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}; /* SoundImpl */
|
|
||||||
|
void SoundManager::stopMusic()
|
||||||
|
{
|
||||||
|
if (music)
|
||||||
|
music->stop();
|
||||||
|
setPlaylist();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SoundManager::streamMusicFull(const std::string& filename)
|
void SoundManager::streamMusicFull(const std::string& filename)
|
||||||
{
|
{
|
||||||
if(!mData) return;
|
|
||||||
|
|
||||||
// Play the sound and tell it to stream, if possible. TODO:
|
// Play the sound and tell it to stream, if possible. TODO:
|
||||||
// Store the reference, the jukebox will need to check status,
|
// Store the reference, the jukebox will need to check status,
|
||||||
// control volume etc.
|
// control volume etc.
|
||||||
if (mData->music)
|
if (music)
|
||||||
mData->music->stop();
|
music->stop();
|
||||||
mData->music = mData->mgr->load(filename);
|
music = mgr->load(filename);
|
||||||
mData->music->setStreaming(true);
|
music->setStreaming(true);
|
||||||
mData->music->setVolume(0.4);
|
music->setVolume(0.4);
|
||||||
mData->music->play();
|
music->play();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera,
|
|
||||||
const ESMS::ESMStore &store, const Files::PathContainer& dataDirs,
|
|
||||||
bool useSound, bool fsstrict, MWWorld::Environment& environment)
|
|
||||||
: mData(NULL)
|
|
||||||
, fsStrict(fsstrict)
|
|
||||||
, mEnvironment(environment)
|
|
||||||
{
|
|
||||||
for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
|
|
||||||
{
|
|
||||||
MP3Lookup((*it) / "Music/Explore/");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(useSound)
|
|
||||||
{
|
|
||||||
Files::PathContainer soundDirs;;
|
|
||||||
for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
|
|
||||||
{
|
|
||||||
soundDirs.push_back( *it / std::string("Sound"));
|
|
||||||
}
|
|
||||||
mData = new SoundImpl(root, camera, store, soundDirs /* Sound */, dataDirs /* Music */, fsstrict);
|
|
||||||
}
|
|
||||||
|
|
||||||
test.name = "";
|
|
||||||
total = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundManager::~SoundManager()
|
|
||||||
{
|
|
||||||
if(mData)
|
|
||||||
delete mData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundManager::streamMusic(const std::string& filename)
|
void SoundManager::streamMusic(const std::string& filename)
|
||||||
{
|
{
|
||||||
if(mData->hasFile(filename, true))
|
std::string filePath = mMusicLibrary.locate(filename, mFSStrict, true).string();
|
||||||
|
if(!filePath.empty())
|
||||||
{
|
{
|
||||||
streamMusicFull(mData->convertPath(filename, true));
|
streamMusicFull(filePath);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundManager::MP3Lookup(const boost::filesystem::path& dir)
|
|
||||||
{
|
|
||||||
boost::filesystem::directory_iterator dir_iter(dir), dir_end;
|
|
||||||
|
|
||||||
std::string mp3extension = ".mp3";
|
|
||||||
for(;dir_iter != dir_end; dir_iter++)
|
|
||||||
{
|
|
||||||
if(boost::filesystem::extension(*dir_iter) == mp3extension)
|
|
||||||
{
|
|
||||||
files.push_back(*dir_iter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::startRandomTitle()
|
void SoundManager::startRandomTitle()
|
||||||
{
|
{
|
||||||
if(!files.empty())
|
if(mCurrentPlaylist && !mCurrentPlaylist->empty())
|
||||||
{
|
{
|
||||||
Files::PathContainer::iterator fileIter = files.begin();
|
Files::PathContainer::const_iterator fileIter = mCurrentPlaylist->begin();
|
||||||
srand( time(NULL) );
|
srand( time(NULL) );
|
||||||
int r = rand() % files.size() + 1; //old random code
|
int r = rand() % mCurrentPlaylist->size() + 1; //old random code
|
||||||
|
|
||||||
std::advance(fileIter, r - 1);
|
std::advance(fileIter, r - 1);
|
||||||
std::string music = fileIter->string();
|
std::string music = fileIter->string();
|
||||||
|
@ -476,105 +326,158 @@ namespace MWSound
|
||||||
bool SoundManager::isMusicPlaying()
|
bool SoundManager::isMusicPlaying()
|
||||||
{
|
{
|
||||||
bool test = false;
|
bool test = false;
|
||||||
if(mData && mData->music)
|
if(music)
|
||||||
{
|
{
|
||||||
test = mData->music->isPlaying();
|
test = music->isPlaying();
|
||||||
}
|
}
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundManager::SoundImpl SoundManager::getMData()
|
bool SoundManager::setPlaylist(std::string playlist)
|
||||||
{
|
{
|
||||||
// bool test = mData->music->isPlaying();
|
const Files::PathContainer* previousPlaylist;
|
||||||
return *mData;
|
previousPlaylist = mCurrentPlaylist;
|
||||||
|
if (playlist == "")
|
||||||
|
{
|
||||||
|
mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict);
|
||||||
|
}
|
||||||
|
else if(mMusicLibrary.containsSection(playlist, mFSStrict))
|
||||||
|
{
|
||||||
|
mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Warning: playlist named " << playlist << " does not exist.\n";
|
||||||
|
}
|
||||||
|
return previousPlaylist == mCurrentPlaylist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundManager::playPlaylist(std::string playlist)
|
||||||
|
{
|
||||||
|
if (playlist == "")
|
||||||
|
{
|
||||||
|
if(!isMusicPlaying())
|
||||||
|
{
|
||||||
|
startRandomTitle();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!setPlaylist(playlist))
|
||||||
|
{
|
||||||
|
startRandomTitle();
|
||||||
|
}
|
||||||
|
else if (!isMusicPlaying())
|
||||||
|
{
|
||||||
|
startRandomTitle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename)
|
void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename)
|
||||||
{
|
{
|
||||||
// The range values are not tested
|
// The range values are not tested
|
||||||
if(!mData) return;
|
std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict, true);
|
||||||
if(mData->hasFile(filename))
|
if(!filePath.empty())
|
||||||
mData->add(mData->convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false);
|
add(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false);
|
||||||
else
|
else
|
||||||
std::cout << "Sound file " << filename << " not found, skipping.\n";
|
std::cout << "Sound file " << filename << " not found, skipping.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SoundManager::sayDone (MWWorld::Ptr ptr) const
|
bool SoundManager::sayDone (MWWorld::Ptr ptr) const
|
||||||
{
|
{
|
||||||
if(!mData) return false;
|
return !isPlaying(ptr, "_say_sound");
|
||||||
return !mData->isPlaying(ptr, "_say_sound");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SoundManager::playSound(const std::string& soundId, float volume, float pitch)
|
void SoundManager::playSound(const std::string& soundId, float volume, float pitch, bool loop)
|
||||||
{
|
{
|
||||||
if(!mData) return;
|
|
||||||
// Play and forget
|
|
||||||
float min, max;
|
float min, max;
|
||||||
const std::string &file = mData->lookup(soundId, volume, min, max);
|
const std::string &file = lookup(soundId, volume, min, max);
|
||||||
if (file != "")
|
if (file != "")
|
||||||
{
|
{
|
||||||
SoundPtr snd = mData->mgr->load(file);
|
SoundPtr snd = mgr->load(file);
|
||||||
|
snd->setRepeat(loop);
|
||||||
snd->setVolume(volume);
|
snd->setVolume(volume);
|
||||||
snd->setRange(min,max);
|
snd->setRange(min,max);
|
||||||
snd->setPitch(pitch);
|
snd->setPitch(pitch);
|
||||||
|
snd->setRelative(true);
|
||||||
snd->play();
|
snd->play();
|
||||||
|
|
||||||
|
if (loop)
|
||||||
|
{
|
||||||
|
// Only add the looping sound once
|
||||||
|
IDMap::iterator it = mLoopedSounds.find(soundId);
|
||||||
|
if(it == mLoopedSounds.end())
|
||||||
|
{
|
||||||
|
mLoopedSounds[soundId] = WSoundPtr(snd);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId,
|
void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId,
|
||||||
float volume, float pitch, bool loop)
|
float volume, float pitch, bool loop, bool untracked)
|
||||||
{
|
{
|
||||||
if(!mData) return;
|
|
||||||
|
|
||||||
// Look up the sound in the ESM data
|
// Look up the sound in the ESM data
|
||||||
float min, max;
|
float min, max;
|
||||||
const std::string &file = mData->lookup(soundId, volume, min, max);
|
const std::string &file = lookup(soundId, volume, min, max);
|
||||||
if (file != "")
|
if (file != "")
|
||||||
mData->add(file, ptr, soundId, volume, pitch, min, max, loop);
|
add(file, ptr, soundId, volume, pitch, min, max, loop, untracked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::stopSound3D (MWWorld::Ptr ptr, const std::string& soundId)
|
void SoundManager::stopSound3D (MWWorld::Ptr ptr, const std::string& soundId)
|
||||||
{
|
{
|
||||||
if(!mData) return;
|
remove(ptr, soundId);
|
||||||
mData->remove(ptr, soundId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::stopSound (MWWorld::Ptr::CellStore *cell)
|
void SoundManager::stopSound (MWWorld::Ptr::CellStore *cell)
|
||||||
{
|
{
|
||||||
if(!mData) return;
|
removeCell(cell);
|
||||||
mData->removeCell(cell);
|
}
|
||||||
|
|
||||||
|
void SoundManager::stopSound(const std::string& soundId)
|
||||||
|
{
|
||||||
|
IDMap::iterator it = mLoopedSounds.find(soundId);
|
||||||
|
if(it != mLoopedSounds.end())
|
||||||
|
{
|
||||||
|
SoundPtr snd = it->second.lock();
|
||||||
|
if(snd) snd->stop();
|
||||||
|
mLoopedSounds.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SoundManager::getSoundPlaying (MWWorld::Ptr ptr, const std::string& soundId) const
|
bool SoundManager::getSoundPlaying (MWWorld::Ptr ptr, const std::string& soundId) const
|
||||||
{
|
{
|
||||||
// Mark all sounds as playing, otherwise the scripts will just
|
// Mark all sounds as playing, otherwise the scripts will just
|
||||||
// keep trying to play them every frame.
|
// keep trying to play them every frame.
|
||||||
if(!mData) return true;
|
|
||||||
|
|
||||||
return mData->isPlaying(ptr, soundId);
|
return isPlaying(ptr, soundId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::updateObject(MWWorld::Ptr ptr)
|
void SoundManager::updateObject(MWWorld::Ptr ptr)
|
||||||
{
|
{
|
||||||
if (mData != NULL)
|
updatePositions(ptr);
|
||||||
{
|
|
||||||
mData->updatePositions(ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::update (float duration)
|
void SoundManager::update (float duration)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell();
|
MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell();
|
||||||
|
static int total = 0;
|
||||||
|
static std::string regionName = "";
|
||||||
|
static float timePassed = 0.0;
|
||||||
|
timePassed += duration;
|
||||||
|
|
||||||
//If the region has changed
|
//If the region has changed
|
||||||
if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10)
|
if(!(current->cell->data.flags & current->cell->Interior) && timePassed >= 10)
|
||||||
{
|
{
|
||||||
timer.restart();
|
|
||||||
if (test.name != current->cell->region)
|
ESM::Region test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region));
|
||||||
|
|
||||||
|
timePassed = 0;
|
||||||
|
if (regionName != current->cell->region)
|
||||||
{
|
{
|
||||||
|
regionName = current->cell->region;
|
||||||
total = 0;
|
total = 0;
|
||||||
test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(test.soundList.size() > 0)
|
if(test.soundList.size() > 0)
|
||||||
|
@ -598,15 +501,15 @@ namespace MWSound
|
||||||
soundIter = test.soundList.begin();
|
soundIter = test.soundList.begin();
|
||||||
while (soundIter != test.soundList.end())
|
while (soundIter != test.soundList.end())
|
||||||
{
|
{
|
||||||
const ESM::NAME32 go = soundIter->sound;
|
const std::string go = soundIter->sound.toString();
|
||||||
int chance = (int) soundIter->chance;
|
int chance = (int) soundIter->chance;
|
||||||
//std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
|
//std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
|
||||||
soundIter++;
|
soundIter++;
|
||||||
if( r - pos < chance)
|
if( r - pos < chance)
|
||||||
{
|
{
|
||||||
//play sound
|
//play sound
|
||||||
std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
|
std::cout << "Sound: " << go <<" Chance:" << chance << "\n";
|
||||||
mEnvironment.mSoundManager->playSound(go.name, 20.0, 1.0);
|
mEnvironment.mSoundManager->playSound(go, 20.0, 1.0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -616,7 +519,7 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
else if(current->cell->data.flags & current->cell->Interior)
|
else if(current->cell->data.flags & current->cell->Interior)
|
||||||
{
|
{
|
||||||
test.name = "";
|
regionName = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <mangle/sound/clients/ogre_output_updater.hpp>
|
||||||
#include <boost/timer.hpp>
|
#include <mangle/sound/clients/ogre_listener_mover.hpp>
|
||||||
|
|
||||||
|
#include <openengine/sound/sndmanager.hpp>
|
||||||
|
|
||||||
|
#include <components/files/filelibrary.hpp>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include <openengine/sound/sndmanager.hpp>
|
|
||||||
#include <components/files/multidircollection.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace Ogre
|
namespace Ogre
|
||||||
|
@ -18,10 +19,15 @@ namespace Ogre
|
||||||
class Camera;
|
class Camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ESMS
|
namespace Mangle
|
||||||
{
|
{
|
||||||
struct ESMStore;
|
namespace Sound
|
||||||
|
{
|
||||||
|
typedef boost::shared_ptr<Sound> SoundPtr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef OEngine::Sound::SoundManagerPtr OEManagerPtr;
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
@ -30,43 +36,94 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
//SoundPtr *music;
|
|
||||||
class SoundManager
|
class SoundManager
|
||||||
{
|
{
|
||||||
// Hide implementation details - engine.cpp is compiling
|
|
||||||
// enough as it is.
|
|
||||||
struct SoundImpl;
|
|
||||||
|
|
||||||
SoundImpl *mData;
|
// This is used for case insensitive and slash-type agnostic file
|
||||||
Files::PathContainer files;
|
// finding. It takes DOS paths (any case, \\ slashes or / slashes)
|
||||||
bool fsStrict;
|
// relative to the sound dir, and translates them into full paths
|
||||||
|
// of existing files in the filesystem, if they exist.
|
||||||
|
bool mFSStrict;
|
||||||
|
|
||||||
MWWorld::Environment& mEnvironment;
|
MWWorld::Environment& mEnvironment;
|
||||||
|
|
||||||
int total;
|
|
||||||
ESM::Region test;
|
|
||||||
boost::timer timer;
|
|
||||||
|
|
||||||
void streamMusicFull (const std::string& filename);
|
void streamMusicFull (const std::string& filename);
|
||||||
///< Play a soundifle
|
///< Play a soundifle
|
||||||
/// \param absolute filename
|
/// \param absolute filename
|
||||||
|
|
||||||
|
/* This is the sound manager. It loades, stores and deletes
|
||||||
|
sounds based on the sound factory it is given.
|
||||||
|
*/
|
||||||
|
OEManagerPtr mgr;
|
||||||
|
Mangle::Sound::SoundPtr music;
|
||||||
|
|
||||||
|
/* This class calls update() on the sound manager each frame
|
||||||
|
using and Ogre::FrameListener
|
||||||
|
*/
|
||||||
|
Mangle::Sound::OgreOutputUpdater updater;
|
||||||
|
|
||||||
|
/* This class tracks the movement of an Ogre::Camera and moves
|
||||||
|
a sound listener automatically to follow it.
|
||||||
|
*/
|
||||||
|
Mangle::Sound::OgreListenerMover cameraTracker;
|
||||||
|
|
||||||
|
typedef std::map<std::string,Mangle::Sound::WSoundPtr> IDMap;
|
||||||
|
typedef std::map<MWWorld::Ptr,IDMap> PtrMap;
|
||||||
|
PtrMap sounds;
|
||||||
|
|
||||||
|
// A list of all sound files used to lookup paths
|
||||||
|
Files::PathContainer mSoundFiles;
|
||||||
|
|
||||||
|
// A library of all Music file paths stored by the folder they are contained in
|
||||||
|
Files::FileLibrary mMusicLibrary;
|
||||||
|
|
||||||
|
// Points to the current playlist of music files stored in the music library
|
||||||
|
const Files::PathContainer* mCurrentPlaylist;
|
||||||
|
|
||||||
|
IDMap mLoopedSounds;
|
||||||
|
|
||||||
|
std::string lookup(const std::string &soundId,
|
||||||
|
float &volume, float &min, float &max);
|
||||||
|
void add(const std::string &file,
|
||||||
|
MWWorld::Ptr ptr, const std::string &id,
|
||||||
|
float volume, float pitch, float min, float max,
|
||||||
|
bool loop, bool untracked=false);
|
||||||
|
void clearAll(PtrMap::iterator& it);
|
||||||
|
void remove(MWWorld::Ptr ptr, const std::string &id = "");
|
||||||
|
bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const;
|
||||||
|
void removeCell(const MWWorld::Ptr::CellStore *cell);
|
||||||
|
void updatePositions(MWWorld::Ptr ptr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store,
|
SoundManager(Ogre::Root*, Ogre::Camera*,
|
||||||
const Files::PathContainer& dataDir, bool useSound, bool fsstrict,
|
const Files::PathContainer& dataDir, bool useSound, bool fsstrict,
|
||||||
MWWorld::Environment& environment);
|
MWWorld::Environment& environment);
|
||||||
~SoundManager();
|
~SoundManager();
|
||||||
|
|
||||||
|
void stopMusic();
|
||||||
|
///< Stops music if it's playing
|
||||||
|
|
||||||
void streamMusic(const std::string& filename);
|
void streamMusic(const std::string& filename);
|
||||||
///< Play a soundifle
|
///< Play a soundifle
|
||||||
/// \param filename name of a sound file in "Music/" in the data directory.
|
/// \param filename name of a sound file in "Music/" in the data directory.
|
||||||
|
|
||||||
void startRandomTitle();
|
void startRandomTitle();
|
||||||
void MP3Lookup(const boost::filesystem::path& dir);
|
///< Starts a random track from the current playlist
|
||||||
|
|
||||||
bool isMusicPlaying();
|
bool isMusicPlaying();
|
||||||
|
///< Returns true if music is playing
|
||||||
|
|
||||||
SoundImpl getMData();
|
bool setPlaylist(std::string playlist="");
|
||||||
|
///< Set the playlist to an existing folder
|
||||||
|
/// \param name of the folder that contains the playlist
|
||||||
|
/// if none is set then it is set to an empty playlist
|
||||||
|
/// \return Return true if the previous playlist was the same
|
||||||
|
|
||||||
|
void playPlaylist(std::string playlist="");
|
||||||
|
///< Start playing music from the selected folder
|
||||||
|
/// \param name of the folder that contains the playlist
|
||||||
|
/// if none is set then it plays from the current playlist
|
||||||
|
|
||||||
void say (MWWorld::Ptr reference, const std::string& filename);
|
void say (MWWorld::Ptr reference, const std::string& filename);
|
||||||
///< Make an actor say some text.
|
///< Make an actor say some text.
|
||||||
|
@ -75,11 +132,11 @@ namespace MWSound
|
||||||
bool sayDone (MWWorld::Ptr reference) const;
|
bool sayDone (MWWorld::Ptr reference) const;
|
||||||
///< Is actor not speaking?
|
///< Is actor not speaking?
|
||||||
|
|
||||||
void playSound (const std::string& soundId, float volume, float pitch);
|
void playSound (const std::string& soundId, float volume, float pitch, bool loop=false);
|
||||||
///< Play a sound, independently of 3D-position
|
///< Play a sound, independently of 3D-position
|
||||||
|
|
||||||
void playSound3D (MWWorld::Ptr reference, const std::string& soundId,
|
void playSound3D (MWWorld::Ptr reference, const std::string& soundId,
|
||||||
float volume, float pitch, bool loop);
|
float volume, float pitch, bool loop, bool untracked=false);
|
||||||
///< Play a sound from an object
|
///< Play a sound from an object
|
||||||
|
|
||||||
void stopSound3D (MWWorld::Ptr reference, const std::string& soundId = "");
|
void stopSound3D (MWWorld::Ptr reference, const std::string& soundId = "");
|
||||||
|
@ -89,6 +146,9 @@ namespace MWSound
|
||||||
void stopSound (MWWorld::Ptr::CellStore *cell);
|
void stopSound (MWWorld::Ptr::CellStore *cell);
|
||||||
///< Stop all sounds for the given cell.
|
///< Stop all sounds for the given cell.
|
||||||
|
|
||||||
|
void stopSound(const std::string& soundId);
|
||||||
|
///< Stop a non-3d looping sound
|
||||||
|
|
||||||
bool getSoundPlaying (MWWorld::Ptr reference, const std::string& soundId) const;
|
bool getSoundPlaying (MWWorld::Ptr reference, const std::string& soundId) const;
|
||||||
///< Is the given sound currently playing on the given object?
|
///< Is the given sound currently playing on the given object?
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
|
#include "class.hpp"
|
||||||
|
#include "containerstore.hpp"
|
||||||
|
|
||||||
MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
|
MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
|
||||||
{
|
{
|
||||||
|
@ -35,6 +37,39 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore)
|
||||||
|
{
|
||||||
|
for (ESMS::CellRefList<ESM::Container, RefData>::List::iterator iter (
|
||||||
|
cellStore.containers.list.begin());
|
||||||
|
iter!=cellStore.containers.list.end(); ++iter)
|
||||||
|
{
|
||||||
|
Ptr container (&*iter, &cellStore);
|
||||||
|
|
||||||
|
Class::get (container).getContainerStore (container).fill (
|
||||||
|
iter->base->inventory, mStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ESMS::CellRefList<ESM::Creature, RefData>::List::iterator iter (
|
||||||
|
cellStore.creatures.list.begin());
|
||||||
|
iter!=cellStore.creatures.list.end(); ++iter)
|
||||||
|
{
|
||||||
|
Ptr container (&*iter, &cellStore);
|
||||||
|
|
||||||
|
Class::get (container).getContainerStore (container).fill (
|
||||||
|
iter->base->inventory, mStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ESMS::CellRefList<ESM::NPC, RefData>::List::iterator iter (
|
||||||
|
cellStore.npcs.list.begin());
|
||||||
|
iter!=cellStore.npcs.list.end(); ++iter)
|
||||||
|
{
|
||||||
|
Ptr container (&*iter, &cellStore);
|
||||||
|
|
||||||
|
Class::get (container).getContainerStore (container).fill (
|
||||||
|
iter->base->inventory, mStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world)
|
MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world)
|
||||||
: mStore (store), mReader (reader), mWorld (world) {}
|
: mStore (store), mReader (reader), mWorld (world) {}
|
||||||
|
|
||||||
|
@ -43,6 +78,8 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y)
|
||||||
std::map<std::pair<int, int>, Ptr::CellStore>::iterator result =
|
std::map<std::pair<int, int>, Ptr::CellStore>::iterator result =
|
||||||
mExteriors.find (std::make_pair (x, y));
|
mExteriors.find (std::make_pair (x, y));
|
||||||
|
|
||||||
|
bool fill = false;
|
||||||
|
|
||||||
if (result==mExteriors.end())
|
if (result==mExteriors.end())
|
||||||
{
|
{
|
||||||
const ESM::Cell *cell = mStore.cells.searchExt (x, y);
|
const ESM::Cell *cell = mStore.cells.searchExt (x, y);
|
||||||
|
@ -63,11 +100,16 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y)
|
||||||
|
|
||||||
result = mExteriors.insert (std::make_pair (
|
result = mExteriors.insert (std::make_pair (
|
||||||
std::make_pair (x, y), Ptr::CellStore (cell))).first;
|
std::make_pair (x, y), Ptr::CellStore (cell))).first;
|
||||||
|
|
||||||
|
fill = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result->second.mState!=Ptr::CellStore::State_Loaded)
|
if (result->second.mState!=Ptr::CellStore::State_Loaded)
|
||||||
result->second.load (mStore, mReader);
|
result->second.load (mStore, mReader);
|
||||||
|
|
||||||
|
if (fill)
|
||||||
|
fillContainers (result->second);
|
||||||
|
|
||||||
return &result->second;
|
return &result->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,16 +117,23 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name)
|
||||||
{
|
{
|
||||||
std::map<std::string, Ptr::CellStore>::iterator result = mInteriors.find (name);
|
std::map<std::string, Ptr::CellStore>::iterator result = mInteriors.find (name);
|
||||||
|
|
||||||
|
bool fill = false;
|
||||||
|
|
||||||
if (result==mInteriors.end())
|
if (result==mInteriors.end())
|
||||||
{
|
{
|
||||||
const ESM::Cell *cell = mStore.cells.findInt (name);
|
const ESM::Cell *cell = mStore.cells.findInt (name);
|
||||||
|
|
||||||
result = mInteriors.insert (std::make_pair (name, Ptr::CellStore (cell))).first;
|
result = mInteriors.insert (std::make_pair (name, Ptr::CellStore (cell))).first;
|
||||||
|
|
||||||
|
fill = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result->second.mState!=Ptr::CellStore::State_Loaded)
|
if (result->second.mState!=Ptr::CellStore::State_Loaded)
|
||||||
result->second.load (mStore, mReader);
|
result->second.load (mStore, mReader);
|
||||||
|
|
||||||
|
if (fill)
|
||||||
|
fillContainers (result->second);
|
||||||
|
|
||||||
return &result->second;
|
return &result->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ namespace MWWorld
|
||||||
|
|
||||||
Ptr::CellStore *getCellStore (const ESM::Cell *cell);
|
Ptr::CellStore *getCellStore (const ESM::Cell *cell);
|
||||||
|
|
||||||
|
void fillContainers (Ptr::CellStore& cellStore);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world);
|
Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world);
|
||||||
|
|
|
@ -77,6 +77,11 @@ namespace MWWorld
|
||||||
throw std::runtime_error ("class does not have a container store");
|
throw std::runtime_error ("class does not have a container store");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InventoryStore& Class::getInventoryStore (const Ptr& ptr) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("class does not have an inventory store");
|
||||||
|
}
|
||||||
|
|
||||||
void Class::lock (const Ptr& ptr, int lockLevel) const
|
void Class::lock (const Ptr& ptr, int lockLevel) const
|
||||||
{
|
{
|
||||||
throw std::runtime_error ("class does not support locking");
|
throw std::runtime_error ("class does not support locking");
|
||||||
|
@ -122,6 +127,16 @@ namespace MWWorld
|
||||||
return Ogre::Vector3 (0, 0, 0);
|
return Ogre::Vector3 (0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<int>, bool> Class::getEquipmentSlots (const Ptr& ptr) const
|
||||||
|
{
|
||||||
|
return std::make_pair (std::vector<int>(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Class::getEquipmentSkill (const Ptr& ptr, const Environment& environment) const
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const Class& Class::get (const std::string& key)
|
const Class& Class::get (const std::string& key)
|
||||||
{
|
{
|
||||||
std::map<std::string, boost::shared_ptr<Class> >::const_iterator iter = sClasses.find (key);
|
std::map<std::string, boost::shared_ptr<Class> >::const_iterator iter = sClasses.find (key);
|
||||||
|
@ -141,4 +156,14 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
sClasses.insert (std::make_pair (key, instance));
|
sClasses.insert (std::make_pair (key, instance));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Class::getUpSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("class does not have an up sound");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Class::getDownSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("class does not have an down sound");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ namespace MWWorld
|
||||||
class Ptr;
|
class Ptr;
|
||||||
class Environment;
|
class Environment;
|
||||||
class ContainerStore;
|
class ContainerStore;
|
||||||
|
class InventoryStore;
|
||||||
|
|
||||||
/// \brief Base class for referenceable esm records
|
/// \brief Base class for referenceable esm records
|
||||||
class Class
|
class Class
|
||||||
|
@ -108,6 +110,10 @@ namespace MWWorld
|
||||||
///< Return container store or throw an exception, if class does not have a
|
///< Return container store or throw an exception, if class does not have a
|
||||||
/// container store (default implementation: throw an exceoption)
|
/// container store (default implementation: throw an exceoption)
|
||||||
|
|
||||||
|
virtual InventoryStore& getInventoryStore (const Ptr& ptr) const;
|
||||||
|
///< Return inventory store or throw an exception, if class does not have a
|
||||||
|
/// inventory store (default implementation: throw an exceoption)
|
||||||
|
|
||||||
virtual void lock (const Ptr& ptr, int lockLevel) const;
|
virtual void lock (const Ptr& ptr, int lockLevel) const;
|
||||||
///< Lock object (default implementation: throw an exception)
|
///< Lock object (default implementation: throw an exception)
|
||||||
|
|
||||||
|
@ -137,6 +143,18 @@ namespace MWWorld
|
||||||
///< Return desired movement vector (determined based on movement settings,
|
///< Return desired movement vector (determined based on movement settings,
|
||||||
/// stance and stats).
|
/// stance and stats).
|
||||||
|
|
||||||
|
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const Ptr& ptr) const;
|
||||||
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
|
/// stay stacked when equipped?
|
||||||
|
///
|
||||||
|
/// Default implementation: return (empty vector, false).
|
||||||
|
|
||||||
|
virtual int getEquipmentSkill (const Ptr& ptr, const Environment& environment)
|
||||||
|
const;
|
||||||
|
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||||
|
/// no such skill.
|
||||||
|
/// (default implementation: return -1)
|
||||||
|
|
||||||
static const Class& get (const std::string& key);
|
static const Class& get (const std::string& key);
|
||||||
///< If there is no class for this \a key, an exception is thrown.
|
///< If there is no class for this \a key, an exception is thrown.
|
||||||
|
|
||||||
|
@ -144,6 +162,14 @@ namespace MWWorld
|
||||||
///< If there is no class for this pointer, an exception is thrown.
|
///< If there is no class for this pointer, an exception is thrown.
|
||||||
|
|
||||||
static void registerClass (const std::string& key, boost::shared_ptr<Class> instance);
|
static void registerClass (const std::string& key, boost::shared_ptr<Class> instance);
|
||||||
|
|
||||||
|
virtual std::string getUpSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the up sound ID of \a ptr or throw an exception, if class does not support ID retrieval
|
||||||
|
/// (default implementation: throw an exception)
|
||||||
|
|
||||||
|
virtual std::string getDownSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval
|
||||||
|
/// (default implementation: throw an exception)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <components/esm/loadcont.hpp>
|
||||||
|
|
||||||
|
#include "manualref.hpp"
|
||||||
|
|
||||||
|
MWWorld::ContainerStore::~ContainerStore() {}
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::begin (int mask)
|
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::begin (int mask)
|
||||||
{
|
{
|
||||||
return ContainerStoreIterator (mask, this);
|
return ContainerStoreIterator (mask, this);
|
||||||
|
@ -17,7 +23,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end()
|
||||||
|
|
||||||
void MWWorld::ContainerStore::add (const Ptr& ptr)
|
void MWWorld::ContainerStore::add (const Ptr& ptr)
|
||||||
{
|
{
|
||||||
/// \todo implement item stocking
|
/// \todo implement item stacking
|
||||||
|
|
||||||
switch (getType (ptr))
|
switch (getType (ptr))
|
||||||
{
|
{
|
||||||
|
@ -36,6 +42,40 @@ void MWWorld::ContainerStore::add (const Ptr& ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS::ESMStore& store)
|
||||||
|
{
|
||||||
|
for (std::vector<ESM::ContItem>::const_iterator iter (items.list.begin()); iter!=items.list.end();
|
||||||
|
++iter)
|
||||||
|
{
|
||||||
|
ManualRef ref (store, iter->item.toString());
|
||||||
|
|
||||||
|
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
||||||
|
{
|
||||||
|
/// \todo implement leveled item lists
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref.getPtr().getRefData().setCount (iter->count);
|
||||||
|
add (ref.getPtr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::ContainerStore::clear()
|
||||||
|
{
|
||||||
|
potions.list.clear();
|
||||||
|
appas.list.clear();
|
||||||
|
armors.list.clear();
|
||||||
|
books.list.clear();
|
||||||
|
clothes.list.clear();
|
||||||
|
ingreds.list.clear();
|
||||||
|
lights.list.clear();
|
||||||
|
lockpicks.list.clear();
|
||||||
|
miscItems.list.clear();
|
||||||
|
probes.list.clear();
|
||||||
|
repairs.list.clear();
|
||||||
|
weapons.list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
int MWWorld::ContainerStore::getType (const Ptr& ptr)
|
int MWWorld::ContainerStore::getType (const Ptr& ptr)
|
||||||
{
|
{
|
||||||
if (ptr.isEmpty())
|
if (ptr.isEmpty())
|
||||||
|
@ -331,6 +371,11 @@ int MWWorld::ContainerStoreIterator::getType() const
|
||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MWWorld::ContainerStore *MWWorld::ContainerStoreIterator::getContainerStore() const
|
||||||
|
{
|
||||||
|
return mContainer;
|
||||||
|
}
|
||||||
|
|
||||||
bool MWWorld::operator== (const ContainerStoreIterator& left, const ContainerStoreIterator& right)
|
bool MWWorld::operator== (const ContainerStoreIterator& left, const ContainerStoreIterator& right)
|
||||||
{
|
{
|
||||||
return left.isEqual (right);
|
return left.isEqual (right);
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
#ifndef GAME_MWWORLD_CONTAINERSTORE_H
|
#ifndef GAME_MWWORLD_CONTAINERSTORE_H
|
||||||
#define GAME_MWWORLD_CONTAINERSTORE_H
|
#define GAME_MWWORLD_CONTAINERSTORE_H
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include <components/esm_store/cell_store.hpp>
|
#include <components/esm_store/cell_store.hpp>
|
||||||
|
|
||||||
#include "refdata.hpp"
|
#include "refdata.hpp"
|
||||||
#include "ptr.hpp"
|
#include "ptr.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct InventoryList;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class ContainerStoreIterator;
|
class ContainerStoreIterator;
|
||||||
|
@ -48,6 +55,8 @@ namespace MWWorld
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual ~ContainerStore();
|
||||||
|
|
||||||
ContainerStoreIterator begin (int mask = Type_All);
|
ContainerStoreIterator begin (int mask = Type_All);
|
||||||
|
|
||||||
ContainerStoreIterator end();
|
ContainerStoreIterator end();
|
||||||
|
@ -60,6 +69,12 @@ namespace MWWorld
|
||||||
/// \attention Do not add items to an existing stack by increasing the count instead of
|
/// \attention Do not add items to an existing stack by increasing the count instead of
|
||||||
/// calling this function!
|
/// calling this function!
|
||||||
|
|
||||||
|
void fill (const ESM::InventoryList& items, const ESMS::ESMStore& store);
|
||||||
|
///< Insert items into *this.
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
///< Empty container.
|
||||||
|
|
||||||
static int getType (const Ptr& ptr);
|
static int getType (const Ptr& ptr);
|
||||||
///< This function throws an exception, if ptr does not point to an object, that can be
|
///< This function throws an exception, if ptr does not point to an object, that can be
|
||||||
/// put into a container.
|
/// put into a container.
|
||||||
|
@ -71,6 +86,7 @@ namespace MWWorld
|
||||||
///
|
///
|
||||||
/// \note The iterator will automatically skip over deleted objects.
|
/// \note The iterator will automatically skip over deleted objects.
|
||||||
class ContainerStoreIterator
|
class ContainerStoreIterator
|
||||||
|
: public std::iterator<std::forward_iterator_tag, Ptr, std::ptrdiff_t, Ptr *, Ptr&>
|
||||||
{
|
{
|
||||||
int mType;
|
int mType;
|
||||||
int mMask;
|
int mMask;
|
||||||
|
@ -126,6 +142,8 @@ namespace MWWorld
|
||||||
|
|
||||||
int getType() const;
|
int getType() const;
|
||||||
|
|
||||||
|
const ContainerStore *getContainerStore() const;
|
||||||
|
|
||||||
friend class ContainerStore;
|
friend class ContainerStore;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
86
apps/openmw/mwworld/inventorystore.cpp
Normal file
86
apps/openmw/mwworld/inventorystore.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
|
||||||
|
#include "inventorystore.hpp"
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "class.hpp"
|
||||||
|
|
||||||
|
void MWWorld::InventoryStore::copySlots (const InventoryStore& store)
|
||||||
|
{
|
||||||
|
// some const-trickery, required because of a flaw in the handling of MW-references and the
|
||||||
|
// resulting workarounds
|
||||||
|
for (std::vector<ContainerStoreIterator>::const_iterator iter (
|
||||||
|
const_cast<InventoryStore&> (store).mSlots.begin());
|
||||||
|
iter!=const_cast<InventoryStore&> (store).mSlots.end(); ++iter)
|
||||||
|
{
|
||||||
|
std::size_t distance = std::distance (const_cast<InventoryStore&> (store).begin(), *iter);
|
||||||
|
|
||||||
|
ContainerStoreIterator slot = begin();
|
||||||
|
|
||||||
|
std::advance (slot, distance);
|
||||||
|
|
||||||
|
mSlots.push_back (slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::InventoryStore::InventoryStore()
|
||||||
|
{
|
||||||
|
for (int i=0; i<Slots; ++i)
|
||||||
|
mSlots.push_back (end());
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
||||||
|
: ContainerStore (store)
|
||||||
|
{
|
||||||
|
copySlots (store);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStore& store)
|
||||||
|
{
|
||||||
|
ContainerStore::operator= (store);
|
||||||
|
mSlots.clear();
|
||||||
|
copySlots (store);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& iterator)
|
||||||
|
{
|
||||||
|
if (slot<0 || slot>=static_cast<int> (mSlots.size()))
|
||||||
|
throw std::runtime_error ("slot number out of range");
|
||||||
|
|
||||||
|
if (iterator.getContainerStore()!=this)
|
||||||
|
throw std::runtime_error ("attempt to equip an item that is not in the inventory");
|
||||||
|
|
||||||
|
if (iterator!=end())
|
||||||
|
{
|
||||||
|
std::pair<std::vector<int>, bool> slots = Class::get (*iterator).getEquipmentSlots (*iterator);
|
||||||
|
|
||||||
|
if (std::find (slots.first.begin(), slots.first.end(), slot)==slots.first.end())
|
||||||
|
throw std::runtime_error ("invalid slot");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \todo restack item previously in this slot (if required)
|
||||||
|
|
||||||
|
/// \todo unstack item pointed to by iterator if required)
|
||||||
|
|
||||||
|
mSlots[slot] = iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot)
|
||||||
|
{
|
||||||
|
if (slot<0 || slot>=static_cast<int> (mSlots.size()))
|
||||||
|
throw std::runtime_error ("slot number out of range");
|
||||||
|
|
||||||
|
if (mSlots[slot]==end())
|
||||||
|
return end();
|
||||||
|
|
||||||
|
if (mSlots[slot]->getRefData().getCount()<1)
|
||||||
|
{
|
||||||
|
// object has been deleted
|
||||||
|
mSlots[slot] = end();
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mSlots[slot];
|
||||||
|
}
|
58
apps/openmw/mwworld/inventorystore.hpp
Normal file
58
apps/openmw/mwworld/inventorystore.hpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef GAME_MWWORLD_INVENTORYSTORE_H
|
||||||
|
#define GAME_MWWORLD_INVENTORYSTORE_H
|
||||||
|
|
||||||
|
#include "containerstore.hpp"
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
///< \brief Variant of the ContainerStore for NPCs
|
||||||
|
class InventoryStore : public ContainerStore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const int Slot_Helmet = 0;
|
||||||
|
static const int Slot_Cuirass = 1;
|
||||||
|
static const int Slot_Greaves = 2;
|
||||||
|
static const int Slot_LeftPauldron = 3;
|
||||||
|
static const int Slot_RightPauldron = 4;
|
||||||
|
static const int Slot_LeftGauntlet = 5;
|
||||||
|
static const int Slot_RightGauntlet = 6;
|
||||||
|
static const int Slot_Boots = 7;
|
||||||
|
static const int Slot_Shirt = 8;
|
||||||
|
static const int Slot_Pants = 9;
|
||||||
|
static const int Slot_Skirt = 10;
|
||||||
|
static const int Slot_Robe = 11;
|
||||||
|
static const int Slot_LeftRing = 12;
|
||||||
|
static const int Slot_RightRing = 13;
|
||||||
|
static const int Slot_Amulet = 14;
|
||||||
|
static const int Slot_Belt = 15;
|
||||||
|
static const int Slot_CarriedRight = 16;
|
||||||
|
static const int Slot_CarriedLeft = 17;
|
||||||
|
static const int Slot_Ammunition = 18;
|
||||||
|
|
||||||
|
static const int Slots = 19;
|
||||||
|
|
||||||
|
static const int Slot_NoSlot = -1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
mutable std::vector<ContainerStoreIterator> mSlots;
|
||||||
|
|
||||||
|
void copySlots (const InventoryStore& store);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
InventoryStore();
|
||||||
|
|
||||||
|
InventoryStore (const InventoryStore& store);
|
||||||
|
|
||||||
|
InventoryStore& operator= (const InventoryStore& store);
|
||||||
|
|
||||||
|
void equip (int slot, const ContainerStoreIterator& iterator);
|
||||||
|
///< \note \a iteartor can be an end-iterator
|
||||||
|
|
||||||
|
ContainerStoreIterator getSlot (int slot);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -496,7 +496,10 @@ WeatherResult WeatherManager::transition(float factor)
|
||||||
void WeatherManager::update(float duration)
|
void WeatherManager::update(float duration)
|
||||||
{
|
{
|
||||||
mWeatherUpdateTime -= duration;
|
mWeatherUpdateTime -= duration;
|
||||||
if (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior())
|
|
||||||
|
bool exterior = (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior());
|
||||||
|
|
||||||
|
if (exterior)
|
||||||
{
|
{
|
||||||
std::string regionstr = mEnvironment->mWorld->getPlayer().getPlayer().getCell()->cell->region;
|
std::string regionstr = mEnvironment->mWorld->getPlayer().getPlayer().getCell()->cell->region;
|
||||||
boost::algorithm::to_lower(regionstr);
|
boost::algorithm::to_lower(regionstr);
|
||||||
|
@ -671,7 +674,7 @@ void WeatherManager::update(float duration)
|
||||||
mRendering->getSkyManager()->secundaDisable();
|
mRendering->getSkyManager()->secundaDisable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCurrentWeather == "thunderstorm" && mNextWeather == "")
|
if (mCurrentWeather == "thunderstorm" && mNextWeather == "" && exterior)
|
||||||
{
|
{
|
||||||
if (mThunderFlash > 0)
|
if (mThunderFlash > 0)
|
||||||
{
|
{
|
||||||
|
@ -730,6 +733,42 @@ void WeatherManager::update(float duration)
|
||||||
mRendering->skyDisable();
|
mRendering->skyDisable();
|
||||||
mRendering->getSkyManager()->setThunder(0.f);
|
mRendering->getSkyManager()->setThunder(0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// play sounds
|
||||||
|
std::string ambientSnd = (mNextWeather == "" ? mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID : "");
|
||||||
|
if (!exterior) ambientSnd = "";
|
||||||
|
if (ambientSnd != "")
|
||||||
|
{
|
||||||
|
if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end())
|
||||||
|
{
|
||||||
|
mSoundsPlaying.push_back(ambientSnd);
|
||||||
|
mEnvironment->mSoundManager->playSound(ambientSnd, 1.0, 1.0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string rainSnd = (mNextWeather == "" ? mWeatherSettings[mCurrentWeather].mRainLoopSoundID : "");
|
||||||
|
if (!exterior) rainSnd = "";
|
||||||
|
if (rainSnd != "")
|
||||||
|
{
|
||||||
|
if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end())
|
||||||
|
{
|
||||||
|
mSoundsPlaying.push_back(rainSnd);
|
||||||
|
mEnvironment->mSoundManager->playSound(rainSnd, 1.0, 1.0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop sounds
|
||||||
|
std::vector<std::string>::iterator it=mSoundsPlaying.begin();
|
||||||
|
while (it!=mSoundsPlaying.end())
|
||||||
|
{
|
||||||
|
if ( *it != ambientSnd && *it != rainSnd)
|
||||||
|
{
|
||||||
|
mEnvironment->mSoundManager->stopSound(*it);
|
||||||
|
it = mSoundsPlaying.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::setHour(const float hour)
|
void WeatherManager::setHour(const float hour)
|
||||||
|
|
|
@ -246,6 +246,8 @@ namespace MWWorld
|
||||||
|
|
||||||
std::map<std::string, std::string> mRegionOverrides;
|
std::map<std::string, std::string> mRegionOverrides;
|
||||||
|
|
||||||
|
std::vector<std::string> mSoundsPlaying;
|
||||||
|
|
||||||
Ogre::String mCurrentWeather;
|
Ogre::String mCurrentWeather;
|
||||||
Ogre::String mNextWeather;
|
Ogre::String mNextWeather;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ add_component_dir (misc
|
||||||
|
|
||||||
add_component_dir (files
|
add_component_dir (files
|
||||||
linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager
|
linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager
|
||||||
|
filelibrary
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (compiler
|
add_component_dir (compiler
|
||||||
|
|
|
@ -95,8 +95,6 @@ namespace Compiler
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ControlParser::parseWhileBody (int keyword, const TokenLoc& loc, Scanner& scanner)
|
bool ControlParser::parseWhileBody (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||||
|
@ -108,7 +106,7 @@ namespace Compiler
|
||||||
Codes expr;
|
Codes expr;
|
||||||
mExprParser.append (expr);
|
mExprParser.append (expr);
|
||||||
|
|
||||||
Generator::jump (loop, -mCodeBlock.size()-expr.size());
|
Generator::jump (loop, -static_cast<int> (mCodeBlock.size()-expr.size()));
|
||||||
|
|
||||||
std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
|
std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
|
||||||
|
|
||||||
|
@ -122,7 +120,7 @@ namespace Compiler
|
||||||
|
|
||||||
Codes loop2;
|
Codes loop2;
|
||||||
|
|
||||||
Generator::jump (loop2, -mCodeBlock.size()-expr.size()-skip.size());
|
Generator::jump (loop2, -static_cast<int> (mCodeBlock.size()-expr.size()-skip.size()));
|
||||||
|
|
||||||
if (loop.size()!=loop2.size())
|
if (loop.size()!=loop2.size())
|
||||||
throw std::logic_error (
|
throw std::logic_error (
|
||||||
|
@ -153,8 +151,6 @@ namespace Compiler
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlParser::ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
ControlParser::ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||||
|
|
|
@ -3,32 +3,68 @@
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
|
||||||
void PathGrid::load(ESMReader &esm)
|
void Pathgrid::load(ESMReader &esm)
|
||||||
{
|
{
|
||||||
esm.getHNT(data, "DATA", 12);
|
esm.getHNT(data, "DATA", 12);
|
||||||
cell = esm.getHNString("NAME");
|
cell = esm.getHNString("NAME");
|
||||||
|
|
||||||
// Remember this file position
|
// keep track of total connections so we can reserve edge vector size
|
||||||
context = esm.getContext();
|
int edgeCount = 0;
|
||||||
|
|
||||||
// Check that the sizes match up. Size = 16 * s2 (path points?)
|
|
||||||
if (esm.isNextSub("PGRP"))
|
if (esm.isNextSub("PGRP"))
|
||||||
{
|
{
|
||||||
esm.skipHSub();
|
esm.getSubHeader();
|
||||||
int size = esm.getSubSize();
|
int size = esm.getSubSize();
|
||||||
if (size != 16 * data.s2)
|
// Check that the sizes match up. Size = 16 * s2 (path points)
|
||||||
esm.fail("Path grid table size mismatch");
|
if (size != static_cast<int> (sizeof(Point) * data.s2))
|
||||||
|
esm.fail("Path point subrecord size mismatch");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int pointCount = data.s2;
|
||||||
|
points.reserve(pointCount);
|
||||||
|
for (int i = 0; i < pointCount; ++i)
|
||||||
|
{
|
||||||
|
Point p;
|
||||||
|
esm.getExact(&p, sizeof(Point));
|
||||||
|
points.push_back(p);
|
||||||
|
edgeCount += p.connectionNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size varies. Path grid chances? Connections? Multiples of 4
|
|
||||||
// suggest either int or two shorts, or perhaps a float. Study
|
|
||||||
// it later.
|
|
||||||
if (esm.isNextSub("PGRC"))
|
if (esm.isNextSub("PGRC"))
|
||||||
{
|
{
|
||||||
esm.skipHSub();
|
esm.getSubHeader();
|
||||||
int size = esm.getSubSize();
|
int size = esm.getSubSize();
|
||||||
if (size % 4 != 0)
|
if (size % sizeof(int) != 0)
|
||||||
esm.fail("PGRC size not a multiple of 4");
|
esm.fail("PGRC size not a multiple of 4");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int rawConnNum = size / sizeof(int);
|
||||||
|
std::vector<int> rawConnections;
|
||||||
|
rawConnections.reserve(rawConnNum);
|
||||||
|
for (int i = 0; i < rawConnNum; ++i)
|
||||||
|
{
|
||||||
|
int currentValue;
|
||||||
|
esm.getT(currentValue);
|
||||||
|
rawConnections.push_back(currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int>::const_iterator rawIt = rawConnections.begin();
|
||||||
|
int pointIndex = 0;
|
||||||
|
edges.reserve(edgeCount);
|
||||||
|
for(PointList::const_iterator it = points.begin(); it != points.end(); it++, pointIndex++)
|
||||||
|
{
|
||||||
|
unsigned char connectionNum = (*it).connectionNum;
|
||||||
|
for (int i = 0; i < connectionNum; ++i) {
|
||||||
|
Edge edge;
|
||||||
|
edge.v0 = pointIndex;
|
||||||
|
edge.v1 = *rawIt;
|
||||||
|
rawIt++;
|
||||||
|
edges.push_back(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,20 +9,37 @@ namespace ESM
|
||||||
/*
|
/*
|
||||||
* Path grid.
|
* Path grid.
|
||||||
*/
|
*/
|
||||||
struct PathGrid
|
struct Pathgrid
|
||||||
{
|
{
|
||||||
struct DATAstruct
|
struct DATAstruct
|
||||||
{
|
{
|
||||||
int x, y; // Grid location, matches cell for exterior cells
|
int x, y; // Grid location, matches cell for exterior cells
|
||||||
short s1; // ?? Usually but not always a power of 2. Doesn't seem
|
short s1; // ?? Usually but not always a power of 2. Doesn't seem
|
||||||
// to have any relation to the size of PGRC.
|
// to have any relation to the size of PGRC.
|
||||||
short s2; // Number of path points? Size of PGRP block is always 16 * s2;
|
short s2; // Number of path points.
|
||||||
}; // 12 bytes
|
}; // 12 bytes
|
||||||
|
|
||||||
|
struct Point // path grid point
|
||||||
|
{
|
||||||
|
int x, y, z; // Location of point
|
||||||
|
unsigned char autogenerated; // autogenerated vs. user coloring flag?
|
||||||
|
unsigned char connectionNum; // number of connections for this point
|
||||||
|
short unknown;
|
||||||
|
}; // 16 bytes
|
||||||
|
|
||||||
|
struct Edge // path grid edge
|
||||||
|
{
|
||||||
|
int v0, v1; // index of points connected with this edge
|
||||||
|
}; // 8 bytes
|
||||||
|
|
||||||
std::string cell; // Cell name
|
std::string cell; // Cell name
|
||||||
DATAstruct data;
|
DATAstruct data;
|
||||||
ESM_Context context; // Context so we can return here later and
|
|
||||||
// finish the job
|
typedef std::vector<Point> PointList;
|
||||||
|
PointList points;
|
||||||
|
|
||||||
|
typedef std::vector<Edge> EdgeList;
|
||||||
|
EdgeList edges;
|
||||||
|
|
||||||
void load(ESMReader &esm);
|
void load(ESMReader &esm);
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace ESMS
|
||||||
|
|
||||||
struct RecList
|
struct RecList
|
||||||
{
|
{
|
||||||
|
virtual ~RecList() {}
|
||||||
|
|
||||||
virtual void load(ESMReader &esm, const std::string &id) = 0;
|
virtual void load(ESMReader &esm, const std::string &id) = 0;
|
||||||
virtual int getSize() = 0;
|
virtual int getSize() = 0;
|
||||||
virtual void listIdentifier (std::vector<std::string>& identifier) const = 0;
|
virtual void listIdentifier (std::vector<std::string>& identifier) const = 0;
|
||||||
|
@ -42,6 +44,8 @@ namespace ESMS
|
||||||
template <typename X>
|
template <typename X>
|
||||||
struct RecListT : RecList
|
struct RecListT : RecList
|
||||||
{
|
{
|
||||||
|
virtual ~RecListT() {}
|
||||||
|
|
||||||
typedef std::map<std::string,X> MapType;
|
typedef std::map<std::string,X> MapType;
|
||||||
|
|
||||||
MapType list;
|
MapType list;
|
||||||
|
@ -90,6 +94,8 @@ namespace ESMS
|
||||||
template <typename X>
|
template <typename X>
|
||||||
struct RecListWithIDT : RecList
|
struct RecListWithIDT : RecList
|
||||||
{
|
{
|
||||||
|
virtual ~RecListWithIDT() {}
|
||||||
|
|
||||||
typedef std::map<std::string,X> MapType;
|
typedef std::map<std::string,X> MapType;
|
||||||
|
|
||||||
MapType list;
|
MapType list;
|
||||||
|
@ -139,6 +145,8 @@ namespace ESMS
|
||||||
template <typename X>
|
template <typename X>
|
||||||
struct RecIDListT : RecList
|
struct RecIDListT : RecList
|
||||||
{
|
{
|
||||||
|
virtual ~RecIDListT() {}
|
||||||
|
|
||||||
typedef std::map<std::string,X> MapType;
|
typedef std::map<std::string,X> MapType;
|
||||||
|
|
||||||
MapType list;
|
MapType list;
|
||||||
|
@ -189,6 +197,8 @@ namespace ESMS
|
||||||
*/
|
*/
|
||||||
struct LTexList : RecList
|
struct LTexList : RecList
|
||||||
{
|
{
|
||||||
|
virtual ~LTexList() {}
|
||||||
|
|
||||||
// TODO: For multiple ESM/ESP files we need one list per file.
|
// TODO: For multiple ESM/ESP files we need one list per file.
|
||||||
std::vector<LandTexture> ltex;
|
std::vector<LandTexture> ltex;
|
||||||
int count;
|
int count;
|
||||||
|
@ -223,6 +233,8 @@ namespace ESMS
|
||||||
*/
|
*/
|
||||||
struct LandList : RecList
|
struct LandList : RecList
|
||||||
{
|
{
|
||||||
|
virtual ~LandList() {}
|
||||||
|
|
||||||
// Map containing all landscapes
|
// Map containing all landscapes
|
||||||
typedef std::map<int, Land*> LandsCol;
|
typedef std::map<int, Land*> LandsCol;
|
||||||
typedef std::map<int, LandsCol> Lands;
|
typedef std::map<int, LandsCol> Lands;
|
||||||
|
@ -296,7 +308,7 @@ namespace ESMS
|
||||||
identifier.push_back (iter->first);
|
identifier.push_back (iter->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
~CellList()
|
virtual ~CellList()
|
||||||
{
|
{
|
||||||
for (IntCells::iterator it = intCells.begin(); it!=intCells.end(); ++it)
|
for (IntCells::iterator it = intCells.begin(); it!=intCells.end(); ++it)
|
||||||
delete it->second;
|
delete it->second;
|
||||||
|
@ -390,9 +402,100 @@ namespace ESMS
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PathgridList : RecList
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
// List of grids for interior cells. Indexed by cell name.
|
||||||
|
typedef std::map<std::string,ESM::Pathgrid*, ciLessBoost> IntGrids;
|
||||||
|
IntGrids intGrids;
|
||||||
|
|
||||||
|
// List of grids for exterior cells. Indexed as extCells[gridX][gridY].
|
||||||
|
typedef std::map<std::pair<int, int>, ESM::Pathgrid*> ExtGrids;
|
||||||
|
ExtGrids extGrids;
|
||||||
|
|
||||||
|
PathgridList() : count(0) {}
|
||||||
|
|
||||||
|
virtual ~PathgridList()
|
||||||
|
{
|
||||||
|
for (IntGrids::iterator it = intGrids.begin(); it!=intGrids.end(); ++it)
|
||||||
|
delete it->second;
|
||||||
|
|
||||||
|
for (ExtGrids::iterator it = extGrids.begin(); it!=extGrids.end(); ++it)
|
||||||
|
delete it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSize() { return count; }
|
||||||
|
|
||||||
|
virtual void listIdentifier (std::vector<std::string>& identifier) const
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void load(ESMReader &esm, const std::string &id)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
ESM::Pathgrid *grid = new ESM::Pathgrid;
|
||||||
|
grid->load(esm);
|
||||||
|
if (grid->data.x == 0 && grid->data.y == 0)
|
||||||
|
{
|
||||||
|
intGrids[grid->cell] = grid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
extGrids[std::make_pair(grid->data.x, grid->data.y)] = grid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pathgrid *find(int cellX, int cellY, std::string cellName) const
|
||||||
|
{
|
||||||
|
Pathgrid *result = search(cellX, cellY, cellName);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("no pathgrid found for cell " + cellName);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pathgrid *search(int cellX, int cellY, std::string cellName) const
|
||||||
|
{
|
||||||
|
Pathgrid *result = NULL;
|
||||||
|
if (cellX == 0 && cellY == 0) // possibly interior
|
||||||
|
{
|
||||||
|
IntGrids::const_iterator it = intGrids.find(cellName);
|
||||||
|
if (it != intGrids.end())
|
||||||
|
result = it->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ExtGrids::const_iterator it = extGrids.find(std::make_pair(cellX, cellY));
|
||||||
|
if (it != extGrids.end())
|
||||||
|
result = it->second;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pathgrid *search(const ESM::Cell &cell) const
|
||||||
|
{
|
||||||
|
int cellX, cellY;
|
||||||
|
if (cell.data.flags & ESM::Cell::Interior)
|
||||||
|
{
|
||||||
|
cellX = cellY = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cellX = cell.data.gridX;
|
||||||
|
cellY = cell.data.gridY;
|
||||||
|
}
|
||||||
|
return search(cellX, cellY, cell.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename X>
|
template <typename X>
|
||||||
struct ScriptListT : RecList
|
struct ScriptListT : RecList
|
||||||
{
|
{
|
||||||
|
virtual ~ScriptListT() {}
|
||||||
|
|
||||||
typedef std::map<std::string,X> MapType;
|
typedef std::map<std::string,X> MapType;
|
||||||
|
|
||||||
MapType list;
|
MapType list;
|
||||||
|
@ -444,6 +547,8 @@ namespace ESMS
|
||||||
template <typename X>
|
template <typename X>
|
||||||
struct IndexListT
|
struct IndexListT
|
||||||
{
|
{
|
||||||
|
virtual ~IndexListT() {}
|
||||||
|
|
||||||
typedef std::map<int, X> MapType;
|
typedef std::map<int, X> MapType;
|
||||||
|
|
||||||
MapType list;
|
MapType list;
|
||||||
|
|
|
@ -74,7 +74,8 @@ namespace ESMS
|
||||||
ScriptListT<Script> scripts;
|
ScriptListT<Script> scripts;
|
||||||
IndexListT<MagicEffect> magicEffects;
|
IndexListT<MagicEffect> magicEffects;
|
||||||
IndexListT<Skill> skills;
|
IndexListT<Skill> skills;
|
||||||
//RecListT<PathGrid> pathgrids;
|
//RecListT<Pathgrid> pathgrids;
|
||||||
|
PathgridList pathgrids;
|
||||||
|
|
||||||
// Special entry which is hardcoded and not loaded from an ESM
|
// Special entry which is hardcoded and not loaded from an ESM
|
||||||
IndexListT<Attribute> attributes;
|
IndexListT<Attribute> attributes;
|
||||||
|
@ -124,7 +125,7 @@ namespace ESMS
|
||||||
recLists[REC_MISC] = &miscItems;
|
recLists[REC_MISC] = &miscItems;
|
||||||
recLists[REC_NPC_] = &npcs;
|
recLists[REC_NPC_] = &npcs;
|
||||||
recLists[REC_NPCC] = &npcChange;
|
recLists[REC_NPCC] = &npcChange;
|
||||||
//recLists[REC_PGRD] = &pathgrids;
|
recLists[REC_PGRD] = &pathgrids;
|
||||||
recLists[REC_PROB] = &probes;
|
recLists[REC_PROB] = &probes;
|
||||||
recLists[REC_RACE] = &races;
|
recLists[REC_RACE] = &races;
|
||||||
recLists[REC_REGN] = ®ions;
|
recLists[REC_REGN] = ®ions;
|
||||||
|
|
120
components/files/filelibrary.cpp
Normal file
120
components/files/filelibrary.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#include "filelibrary.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
namespace Files
|
||||||
|
{
|
||||||
|
// Looks for a string in a vector of strings
|
||||||
|
bool containsVectorString(const StringVector& list, const std::string& str)
|
||||||
|
{
|
||||||
|
for (StringVector::const_iterator iter = list.begin();
|
||||||
|
iter != list.end(); iter++)
|
||||||
|
{
|
||||||
|
if (*iter == str)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches a path and adds the results to the library
|
||||||
|
void FileLibrary::add(const boost::filesystem::path &root, bool recursive, bool strict,
|
||||||
|
const StringVector &acceptableExtensions)
|
||||||
|
{
|
||||||
|
if (!boost::filesystem::exists(root))
|
||||||
|
{
|
||||||
|
std::cout << "Warning " << root.string() << " does not exist.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fileExtension;
|
||||||
|
std::string type;
|
||||||
|
|
||||||
|
// remember the last location of the priority list when listing new items
|
||||||
|
int length = mPriorityList.size();
|
||||||
|
|
||||||
|
// First makes a list of all candidate files
|
||||||
|
FileLister(root, mPriorityList, recursive);
|
||||||
|
|
||||||
|
// Then sort these files into sections according to the folder they belong to
|
||||||
|
for (PathContainer::iterator listIter = mPriorityList.begin() + length;
|
||||||
|
listIter != mPriorityList.end(); ++listIter)
|
||||||
|
{
|
||||||
|
if( !acceptableExtensions.empty() )
|
||||||
|
{
|
||||||
|
fileExtension = boost::filesystem::path (listIter->extension()).string();
|
||||||
|
boost::algorithm::to_lower(fileExtension);
|
||||||
|
if(!containsVectorString(acceptableExtensions, fileExtension))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = boost::filesystem::path (listIter->parent_path().leaf()).string();
|
||||||
|
if (!strict)
|
||||||
|
boost::algorithm::to_lower(type);
|
||||||
|
|
||||||
|
mMap[type].push_back(*listIter);
|
||||||
|
// std::cout << "Added path: " << listIter->string() << " in section "<< type <<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the named section exists
|
||||||
|
bool FileLibrary::containsSection(std::string sectionName, bool strict)
|
||||||
|
{
|
||||||
|
if (!strict)
|
||||||
|
boost::algorithm::to_lower(sectionName);
|
||||||
|
StringPathContMap::const_iterator mapIter = mMap.find(sectionName);
|
||||||
|
if (mapIter == mMap.end())
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a pointer to const for a section of the library
|
||||||
|
const PathContainer* FileLibrary::section(std::string sectionName, bool strict)
|
||||||
|
{
|
||||||
|
if (!strict)
|
||||||
|
boost::algorithm::to_lower(sectionName);
|
||||||
|
StringPathContMap::const_iterator mapIter = mMap.find(sectionName);
|
||||||
|
if (mapIter == mMap.end())
|
||||||
|
{
|
||||||
|
//std::cout << "Empty\n";
|
||||||
|
return &mEmptyPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return &(mapIter->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches the library for an item and returns a boost path to it
|
||||||
|
boost::filesystem::path FileLibrary::locate(std::string item, bool strict, bool ignoreExtensions, std::string sectionName)
|
||||||
|
{
|
||||||
|
boost::filesystem::path result("");
|
||||||
|
if (sectionName == "")
|
||||||
|
{
|
||||||
|
return FileListLocator(mPriorityList, boost::filesystem::path(item), strict, ignoreExtensions);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!containsSection(sectionName, strict))
|
||||||
|
{
|
||||||
|
std::cout << "Warning: There is no section named " << sectionName << "\n";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = FileListLocator(mMap[sectionName], boost::filesystem::path(item), strict, ignoreExtensions);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints all the available sections, used for debugging
|
||||||
|
void FileLibrary::printSections()
|
||||||
|
{
|
||||||
|
for(StringPathContMap::const_iterator mapIter = mMap.begin();
|
||||||
|
mapIter != mMap.end(); mapIter++)
|
||||||
|
{
|
||||||
|
std::cout << mapIter->first <<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
components/files/filelibrary.hpp
Normal file
49
components/files/filelibrary.hpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef COMPONENTS_FILES_FILELIBRARY_HPP
|
||||||
|
#define COMPONENTS_FILES_FILELIBRARY_HPP
|
||||||
|
|
||||||
|
#include <components/files/fileops.hpp>
|
||||||
|
|
||||||
|
namespace Files
|
||||||
|
{
|
||||||
|
typedef std::map<std::string, PathContainer> StringPathContMap;
|
||||||
|
typedef std::vector<std::string> StringVector;
|
||||||
|
|
||||||
|
/// Looks for a string in a vector of strings
|
||||||
|
bool containsVectorString(const StringVector& list, const std::string& str);
|
||||||
|
|
||||||
|
/// \brief Searches directories and makes lists of files according to folder name
|
||||||
|
class FileLibrary
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
StringPathContMap mMap;
|
||||||
|
PathContainer mEmptyPath;
|
||||||
|
PathContainer mPriorityList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Searches a path and adds the results to the library
|
||||||
|
/// Recursive search and fs strict options are available
|
||||||
|
/// Takes a vector of acceptable files extensions, if none is given it lists everything.
|
||||||
|
void add(const boost::filesystem::path &root, bool recursive, bool strict,
|
||||||
|
const StringVector &acceptableExtensions);
|
||||||
|
|
||||||
|
/// Returns true if the named section exists
|
||||||
|
/// You can run this check before running section()
|
||||||
|
bool containsSection(std::string sectionName, bool strict);
|
||||||
|
|
||||||
|
/// Returns a pointer to const for a section of the library
|
||||||
|
/// which is essentially a PathContainer.
|
||||||
|
/// If the section does not exists it returns a pointer to an empty path.
|
||||||
|
const PathContainer* section(std::string sectionName, bool strict);
|
||||||
|
|
||||||
|
/// Searches the library for an item and returns a boost path to it
|
||||||
|
/// Optionally you can provide a specific section
|
||||||
|
/// The result is the first that comes up according to alphabetical
|
||||||
|
/// section naming
|
||||||
|
boost::filesystem::path locate(std::string item, bool strict, bool ignoreExtensions, std::string sectionName="");
|
||||||
|
|
||||||
|
/// Prints all the available sections, used for debugging
|
||||||
|
void printSections();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,9 @@
|
||||||
#include "fileops.hpp"
|
#include "fileops.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
namespace Files
|
namespace Files
|
||||||
{
|
{
|
||||||
|
@ -9,4 +13,107 @@ bool isFile(const char *name)
|
||||||
return boost::filesystem::exists(boost::filesystem::path(name));
|
return boost::filesystem::exists(boost::filesystem::path(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the last part of the superset matches the subset
|
||||||
|
bool endingMatches(const std::string& superset, const std::string& subset)
|
||||||
|
{
|
||||||
|
if (subset.length() > superset.length())
|
||||||
|
return false;
|
||||||
|
return superset.substr(superset.length() - subset.length()) == subset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes a list of files from a directory
|
||||||
|
void FileLister( boost::filesystem::path currentPath, Files::PathContainer& list, bool recursive)
|
||||||
|
{
|
||||||
|
if (!boost::filesystem::exists(currentPath))
|
||||||
|
{
|
||||||
|
std::cout << "WARNING: " << currentPath.string() << " does not exist.\n";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
for ( boost::filesystem::recursive_directory_iterator end, itr(currentPath.string());
|
||||||
|
itr != end; ++itr )
|
||||||
|
{
|
||||||
|
if ( boost::filesystem::is_regular_file(*itr))
|
||||||
|
list.push_back(itr->path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( boost::filesystem::directory_iterator end, itr(currentPath.string());
|
||||||
|
itr != end; ++itr )
|
||||||
|
{
|
||||||
|
if ( boost::filesystem::is_regular_file(*itr))
|
||||||
|
list.push_back(itr->path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locates path in path container
|
||||||
|
boost::filesystem::path FileListLocator (const Files::PathContainer& list, const boost::filesystem::path& toFind,
|
||||||
|
bool strict, bool ignoreExtensions)
|
||||||
|
{
|
||||||
|
boost::filesystem::path result("");
|
||||||
|
if (list.empty())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
std::string toFindStr;
|
||||||
|
if (ignoreExtensions)
|
||||||
|
toFindStr = boost::filesystem::basename(toFind);
|
||||||
|
else
|
||||||
|
toFindStr = toFind.string();
|
||||||
|
|
||||||
|
std::string fullPath;
|
||||||
|
|
||||||
|
// The filesystems slash sets the default slash
|
||||||
|
std::string slash;
|
||||||
|
std::string wrongslash;
|
||||||
|
if(list[0].string().find("\\") != std::string::npos)
|
||||||
|
{
|
||||||
|
slash = "\\";
|
||||||
|
wrongslash = "/";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slash = "/";
|
||||||
|
wrongslash = "\\";
|
||||||
|
}
|
||||||
|
|
||||||
|
// The file being looked for is converted to the new slash
|
||||||
|
if(toFindStr.find(wrongslash) != std::string::npos )
|
||||||
|
{
|
||||||
|
boost::replace_all(toFindStr, wrongslash, slash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strict)
|
||||||
|
{
|
||||||
|
boost::algorithm::to_lower(toFindStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Files::PathContainer::const_iterator it = list.begin(); it != list.end(); ++it)
|
||||||
|
{
|
||||||
|
fullPath = it->string();
|
||||||
|
if (ignoreExtensions)
|
||||||
|
fullPath.erase(fullPath.length() -
|
||||||
|
boost::filesystem::path (it->extension()).string().length());
|
||||||
|
|
||||||
|
if (!strict)
|
||||||
|
{
|
||||||
|
boost::algorithm::to_lower(fullPath);
|
||||||
|
}
|
||||||
|
if(endingMatches(fullPath, toFindStr))
|
||||||
|
{
|
||||||
|
result = *it;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overloaded form of the locator that takes a string and returns a string
|
||||||
|
std::string FileListLocator (const Files::PathContainer& list,const std::string& toFind, bool strict, bool ignoreExtensions)
|
||||||
|
{
|
||||||
|
return FileListLocator(list, boost::filesystem::path(toFind), strict, ignoreExtensions).string();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
#ifndef COMPONENTS_FILES_FILEOPS_HPP
|
#ifndef COMPONENTS_FILES_FILEOPS_HPP
|
||||||
#define COMPONENTS_FILES_FILEOPS_HPP
|
#define COMPONENTS_FILES_FILEOPS_HPP
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
namespace Files
|
namespace Files
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -8,6 +14,25 @@ namespace Files
|
||||||
///\param [in] name - filename
|
///\param [in] name - filename
|
||||||
bool isFile(const char *name);
|
bool isFile(const char *name);
|
||||||
|
|
||||||
|
/// A vector of Boost Paths, very handy
|
||||||
|
typedef std::vector<boost::filesystem::path> PathContainer;
|
||||||
|
|
||||||
|
/// Makes a list of files from a directory by taking a boost
|
||||||
|
/// path and a Path Container and adds to the Path container
|
||||||
|
/// all files in the path. It has a recursive option.
|
||||||
|
void FileLister( boost::filesystem::path currentPath, Files::PathContainer& list, bool recursive);
|
||||||
|
|
||||||
|
/// Locates boost path in path container
|
||||||
|
/// returns the path from the container
|
||||||
|
/// that contains the searched path.
|
||||||
|
/// If it's not found it returns and empty path
|
||||||
|
/// Takes care of slashes, backslashes and it has a strict option.
|
||||||
|
boost::filesystem::path FileListLocator (const Files::PathContainer& list, const boost::filesystem::path& toFind,
|
||||||
|
bool strict, bool ignoreExtensions);
|
||||||
|
|
||||||
|
/// Overloaded form of the locator that takes a string and returns a string
|
||||||
|
std::string FileListLocator (const Files::PathContainer& list,const std::string& toFind, bool strict, bool ignoreExtensions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* COMPONENTS_FILES_FILEOPS_HPP */
|
#endif /* COMPONENTS_FILES_FILEOPS_HPP */
|
||||||
|
|
|
@ -177,6 +177,8 @@ void NIFFile::parse()
|
||||||
records[i]->post(this);
|
records[i]->post(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \todo move to the write cpp file
|
||||||
|
|
||||||
void NiSkinInstance::post(NIFFile *nif)
|
void NiSkinInstance::post(NIFFile *nif)
|
||||||
{
|
{
|
||||||
int bnum = bones.length();
|
int bnum = bones.length();
|
||||||
|
|
|
@ -100,6 +100,8 @@ struct Record
|
||||||
/// Does post-processing, after the entire tree is loaded
|
/// Does post-processing, after the entire tree is loaded
|
||||||
virtual void post(NIFFile *nif) {}
|
virtual void post(NIFFile *nif) {}
|
||||||
|
|
||||||
|
virtual ~Record() {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Use these later if you want custom allocation of all NIF objects
|
Use these later if you want custom allocation of all NIF objects
|
||||||
|
|
||||||
|
|
|
@ -1330,6 +1330,9 @@ void NIFLoader::loadResource(Resource *resource)
|
||||||
|
|
||||||
(*iter)->addBoneAssignment(vba);
|
(*iter)->addBoneAssignment(vba);
|
||||||
}
|
}
|
||||||
|
//Don't link on npc parts to eliminate redundant skeletons
|
||||||
|
//Will have to be changed later slightly for robes/skirts
|
||||||
|
if(triname == "")
|
||||||
mesh->_notifySkeleton(mSkel);
|
mesh->_notifySkeleton(mSkel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 14b2851e72f610ae81dd296598867e6fb0babd2a
|
|
3
libs/mangle/.gitignore
vendored
Normal file
3
libs/mangle/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
upload_docs.sh
|
||||||
|
docs
|
||||||
|
*~
|
1510
libs/mangle/Doxyfile
Normal file
1510
libs/mangle/Doxyfile
Normal file
File diff suppressed because it is too large
Load diff
26
libs/mangle/LICENSE.txt
Normal file
26
libs/mangle/LICENSE.txt
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
Minimal Abstraction Game Layer (Mangle) is licensed under the
|
||||||
|
'zlib/libpng' license:
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Copyright (c) 2009 Nicolay Korslund
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
|
129
libs/mangle/README.txt
Normal file
129
libs/mangle/README.txt
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
Welcome to Mangle v0.1
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Written by: Nicolay Korslund (korslund@gmail.com)
|
||||||
|
License: zlib/png (see LICENSE.txt)
|
||||||
|
WWW: http://asm-soft.com/mangle/
|
||||||
|
Documentation: http://asm-soft.com/mangle/docs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Mangle is the project name for a small set of generic interfaces for
|
||||||
|
various game middleware libraries, such as sound, input, graphics, and
|
||||||
|
so on. You can imagine that it stands for "Minimal Abstraction Game
|
||||||
|
Layer", if you like. It will consist of several more or less
|
||||||
|
independent modules, one for each of these areas. These may be used
|
||||||
|
together to build an entire game engine, or they can be used
|
||||||
|
individually as separate libraries.
|
||||||
|
|
||||||
|
However, Mangle does NOT actually implement a game engine, or any new
|
||||||
|
fundamental functionality. More on that below.
|
||||||
|
|
||||||
|
Currently there's modules for sound and streams / archives (virtual
|
||||||
|
file systems.) More will come in the future (including input, 2D/3D
|
||||||
|
graphics, GUI, physics, and more.)
|
||||||
|
|
||||||
|
|
||||||
|
Main idea
|
||||||
|
---------
|
||||||
|
|
||||||
|
The idea behind Mangle is to provide a uniform, consistent interface
|
||||||
|
to other game libraries. The library does not provide ANY
|
||||||
|
functionality on its own. Instead it connects to a backend
|
||||||
|
implementation of your choice (or of your making.)
|
||||||
|
|
||||||
|
The Sound module, for example, currently has backends for OpenAL
|
||||||
|
(output only), FFmpeg (input only) and for Audiere. Hopefully we'll
|
||||||
|
add IrrKlang, FMod, DirectSound, Miles and more in the future. It can
|
||||||
|
combine libraries to get more complete functionality (like using
|
||||||
|
OpenAL for output and FFmpeg to decode sound files), and it's also
|
||||||
|
easy to write your own backend if you're using a different (or
|
||||||
|
home-brewed) sound system.
|
||||||
|
|
||||||
|
Regardless of what backend you use, the front-end interfaces (found
|
||||||
|
eg. in sound/output.h) is identical, and as a library user you
|
||||||
|
shouldn't notice much difference at all if you swap one backend for
|
||||||
|
another at a later point. It should Just Work.
|
||||||
|
|
||||||
|
The interfaces themselves are also quite simple. Setting up a sound
|
||||||
|
stream from FFmpeg or other decoder into OpenAL can be quite hairy -
|
||||||
|
but with Mangle the hairy parts have already been written for you. You
|
||||||
|
just plug the parts together.
|
||||||
|
|
||||||
|
The goal in the long run is to support a wide variety of game-related
|
||||||
|
libraries, and as many backend libraries (free and commercial) as
|
||||||
|
possible, so that you the user will have to write as little code as
|
||||||
|
possible.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
What is it good for
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The main point of Mangle, as we said above, is that it connects to any
|
||||||
|
library of your choice "behind the scenes" but provides the same,
|
||||||
|
super-simple interface front-end for all of them. There can benefit
|
||||||
|
you in many ways:
|
||||||
|
|
||||||
|
- If you want to use a new library that Mangle support. You don't have
|
||||||
|
to scour the net for tutorials and usage examples, since much of the
|
||||||
|
common usage code is already included in the implementation classes.
|
||||||
|
|
||||||
|
- If you don't want to pollute your code with library-specific code.
|
||||||
|
The Mangle interfaces can help you keep your code clean, and its
|
||||||
|
user interface is often simpler than the exteral library one.
|
||||||
|
|
||||||
|
- If you want to quickly connect different libraries together, it
|
||||||
|
really helps if they speak a common language. The Mangle interfaces
|
||||||
|
are exactly that - a common language between libraries. Do you need
|
||||||
|
Audiere to load sounds from a weird archive format only implemented
|
||||||
|
for PhysFS, all channeled through the OGRE resource system? No
|
||||||
|
problem!
|
||||||
|
|
||||||
|
- If you are creating a library that depends on a specific feature
|
||||||
|
(such as sound), but you don't want to lock your users into any
|
||||||
|
specific sound library. Mangle works as an abstraction that lets
|
||||||
|
your users select their own implementation.
|
||||||
|
|
||||||
|
- If you want to support multiple backends for your game/app, or want
|
||||||
|
to make it possible to easily switch backends later. You can select
|
||||||
|
backends at compile time or even at runtime. For example you might
|
||||||
|
want to switch to to a commercial sound library at a later stage in
|
||||||
|
development, or you may want to use a different input library on
|
||||||
|
console platforms than on PC.
|
||||||
|
|
||||||
|
The Mangle implementations are extremely light-weight - often just one
|
||||||
|
or two cpp/h pairs per module. You can plug them directly into your
|
||||||
|
program, there's no separate library building step required.
|
||||||
|
|
||||||
|
Since the library aims to be very modularly put together, you can
|
||||||
|
also, in many cases, just copy-and-paste the parts you need and ignore
|
||||||
|
the rest. Or modify stuff without fearing that the whole 'system' will
|
||||||
|
come crashing down, because there is no big 'system' to speak of.
|
||||||
|
|
||||||
|
|
||||||
|
Past and future
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Mangle started out as (and still is) a spin-off from OpenMW, another
|
||||||
|
project I am personally working on ( http://openmw.com/ ). OpenMW is
|
||||||
|
an attempt to recreate the engine behind the commercial game
|
||||||
|
Morrowind, using only open source software.
|
||||||
|
|
||||||
|
The projects are still tightly interlinked, and they will continue to
|
||||||
|
be until OpenMW is finished. Most near-future work on Mangle will be
|
||||||
|
focused chiefly on OpenMW at the moment. However I will gladly include
|
||||||
|
external contributions and suggestions that are not OpenMW-related if
|
||||||
|
someone sends them to me.
|
||||||
|
|
||||||
|
|
||||||
|
Conclusion
|
||||||
|
----------
|
||||||
|
|
||||||
|
As you might have guessed, Mangle is more a concept in development
|
||||||
|
than a finished library right now.
|
||||||
|
|
||||||
|
All feedback, ideas, concepts, questions and code are very
|
||||||
|
welcome. Send them to: korslund@gmail.com
|
||||||
|
|
||||||
|
I will put up a forum later as well if there's enough interest.
|
29
libs/mangle/input/clients/ogre_input_capture.hpp
Normal file
29
libs/mangle/input/clients/ogre_input_capture.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef MANGLE_INPUT_OGREINPUTFRAME_H
|
||||||
|
#define MANGLE_INPUT_OGREINPUTFRAME_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
This Ogre FrameListener calls capture() on an input driver every frame.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <OgreFrameListener.h>
|
||||||
|
#include "../driver.hpp"
|
||||||
|
|
||||||
|
namespace Mangle {
|
||||||
|
namespace Input {
|
||||||
|
|
||||||
|
struct OgreInputCapture : Ogre::FrameListener
|
||||||
|
{
|
||||||
|
Mangle::Input::Driver &driver;
|
||||||
|
|
||||||
|
OgreInputCapture(Mangle::Input::Driver &drv)
|
||||||
|
: driver(drv) {}
|
||||||
|
|
||||||
|
bool frameStarted(const Ogre::FrameEvent &evt)
|
||||||
|
{
|
||||||
|
driver.capture();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif
|
69
libs/mangle/input/driver.hpp
Normal file
69
libs/mangle/input/driver.hpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef MANGLE_INPUT_DRIVER_H
|
||||||
|
#define MANGLE_INPUT_DRIVER_H
|
||||||
|
|
||||||
|
#include "event.hpp"
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
/** Input::Driver is the main interface to any input system that
|
||||||
|
handles keyboard and/or mouse input, along with any other
|
||||||
|
input source like joysticks.
|
||||||
|
|
||||||
|
It is really a generalized event system, and could also be
|
||||||
|
used for non-input related events. The definition of the event
|
||||||
|
codes and structures are entirely dependent on the
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
A system-independent key code list will be found in keys.hpp,
|
||||||
|
and input drivers should privide optional translations to/from
|
||||||
|
this list for full compatibility.
|
||||||
|
*/
|
||||||
|
struct Driver
|
||||||
|
{
|
||||||
|
Driver() {}
|
||||||
|
virtual ~Driver() {}
|
||||||
|
|
||||||
|
/** Captures input and produces the relevant events from it. An
|
||||||
|
event callback must be set with setEvent(), or all events
|
||||||
|
will be ignored.
|
||||||
|
*/
|
||||||
|
virtual void capture() = 0;
|
||||||
|
|
||||||
|
/** Check the state of a given key or button. The key/button
|
||||||
|
definitions depends on the driver.
|
||||||
|
*/
|
||||||
|
virtual bool isDown(int index) = 0;
|
||||||
|
|
||||||
|
/** Show or hide system mouse cursor
|
||||||
|
*/
|
||||||
|
virtual void showMouse(bool show) = 0;
|
||||||
|
|
||||||
|
/** Set the event handler for input events. The evt->event()
|
||||||
|
function is called for each event. The meaning of the index
|
||||||
|
and *p parameters will be specific to each driver and to
|
||||||
|
each input system.
|
||||||
|
*/
|
||||||
|
void setEvent(EventPtr evt)
|
||||||
|
{ event = evt; }
|
||||||
|
|
||||||
|
/** Instigate an event. Is used internally for all events, but
|
||||||
|
can also be called from the outside to "fake" events from
|
||||||
|
this driver.
|
||||||
|
*/
|
||||||
|
void makeEvent(Event::Type type, int index, const void *p=NULL)
|
||||||
|
{
|
||||||
|
if(event)
|
||||||
|
event->event(type,index,p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Holds the event callback set byt setEvent()
|
||||||
|
EventPtr event;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<Driver> DriverPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
46
libs/mangle/input/event.hpp
Normal file
46
libs/mangle/input/event.hpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef MANGLE_INPUT_EVENT_H
|
||||||
|
#define MANGLE_INPUT_EVENT_H
|
||||||
|
|
||||||
|
#include "../tools/shared_ptr.hpp"
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
/** Generic callback for input events. The meaning of the
|
||||||
|
parameters depend on the system producing the events.
|
||||||
|
*/
|
||||||
|
struct Event
|
||||||
|
{
|
||||||
|
/// Event types
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
EV_Unknown = 1, // Unknown event type
|
||||||
|
EV_KeyDown = 2, // Keyboard button was pressed
|
||||||
|
EV_KeyUp = 4, // Keyboard button was released
|
||||||
|
EV_Keyboard = 6, // All keyboard events
|
||||||
|
|
||||||
|
EV_MouseMove = 8, // Mouse movement
|
||||||
|
EV_MouseDown = 16, // Mouse button pressed
|
||||||
|
EV_MouseUp = 32, // Mouse button released
|
||||||
|
EV_Mouse = 56, // All mouse events
|
||||||
|
|
||||||
|
EV_ALL = 63 // All events
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Called upon all events. The first parameter give the event
|
||||||
|
type, the second gives additional data (usually the local
|
||||||
|
keysym or button index as defined by the driver), and the
|
||||||
|
pointer points to the full custom event structure provided by
|
||||||
|
the driver (the type may vary depending on the EventType,
|
||||||
|
this is defined in the Driver documentation.)
|
||||||
|
*/
|
||||||
|
virtual void event(Type type, int index, const void *p) = 0;
|
||||||
|
virtual ~Event() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<Event> EventPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
47
libs/mangle/input/filters/eventlist.hpp
Normal file
47
libs/mangle/input/filters/eventlist.hpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef MANGLE_INPUT_EVENTLIST_H
|
||||||
|
#define MANGLE_INPUT_EVENTLIST_H
|
||||||
|
|
||||||
|
#include "../event.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
/** And Event handler that distributes each event to a list of
|
||||||
|
other handlers. Supports filtering events by their Type
|
||||||
|
parameter.
|
||||||
|
*/
|
||||||
|
struct EventList : Event
|
||||||
|
{
|
||||||
|
struct Filter
|
||||||
|
{
|
||||||
|
EventPtr evt;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
std::vector<Filter> list;
|
||||||
|
|
||||||
|
void add(EventPtr e, int flags = EV_ALL)
|
||||||
|
{
|
||||||
|
Filter f;
|
||||||
|
f.evt = e;
|
||||||
|
f.flags = flags;
|
||||||
|
list.push_back(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void event(Type type, int index, const void *p)
|
||||||
|
{
|
||||||
|
std::vector<Filter>::iterator it;
|
||||||
|
|
||||||
|
for(it=list.begin(); it!=list.end(); it++)
|
||||||
|
{
|
||||||
|
if(type & it->flags)
|
||||||
|
it->evt->event(type,index,p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<EventList> EventListPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
148
libs/mangle/input/servers/ois_driver.cpp
Normal file
148
libs/mangle/input/servers/ois_driver.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#include "ois_driver.hpp"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <OgreRenderWindow.h>
|
||||||
|
#include <OIS/OIS.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE_CC__
|
||||||
|
#include <Carbon/Carbon.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace Mangle::Input;
|
||||||
|
using namespace OIS;
|
||||||
|
|
||||||
|
struct Mangle::Input::OISListener : OIS::KeyListener, OIS::MouseListener
|
||||||
|
{
|
||||||
|
OISDriver &drv;
|
||||||
|
|
||||||
|
OISListener(OISDriver &driver)
|
||||||
|
: drv(driver) {}
|
||||||
|
|
||||||
|
bool keyPressed( const OIS::KeyEvent &arg )
|
||||||
|
{
|
||||||
|
drv.makeEvent(Event::EV_KeyDown, arg.key, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keyReleased( const OIS::KeyEvent &arg )
|
||||||
|
{
|
||||||
|
drv.makeEvent(Event::EV_KeyUp, arg.key, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
|
||||||
|
{
|
||||||
|
// Mouse button events are handled as key events
|
||||||
|
// TODO: Translate mouse buttons into pseudo-keysyms
|
||||||
|
drv.makeEvent(Event::EV_MouseDown, id, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
|
||||||
|
{
|
||||||
|
// TODO: ditto
|
||||||
|
drv.makeEvent(Event::EV_MouseUp, id, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mouseMoved( const OIS::MouseEvent &arg )
|
||||||
|
{
|
||||||
|
drv.makeEvent(Event::EV_MouseMove, -1, &arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
OISDriver::OISDriver(Ogre::RenderWindow *window, bool exclusive)
|
||||||
|
{
|
||||||
|
assert(window);
|
||||||
|
|
||||||
|
size_t windowHnd;
|
||||||
|
|
||||||
|
window->getCustomAttribute("WINDOW", &windowHnd);
|
||||||
|
|
||||||
|
std::ostringstream windowHndStr;
|
||||||
|
ParamList pl;
|
||||||
|
|
||||||
|
windowHndStr << windowHnd;
|
||||||
|
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
|
||||||
|
|
||||||
|
// Set non-exclusive mouse and keyboard input if the user requested
|
||||||
|
// it.
|
||||||
|
if(!exclusive)
|
||||||
|
{
|
||||||
|
#if defined OIS_WIN32_PLATFORM
|
||||||
|
pl.insert(std::make_pair(std::string("w32_mouse"),
|
||||||
|
std::string("DISCL_FOREGROUND" )));
|
||||||
|
pl.insert(std::make_pair(std::string("w32_mouse"),
|
||||||
|
std::string("DISCL_NONEXCLUSIVE")));
|
||||||
|
pl.insert(std::make_pair(std::string("w32_keyboard"),
|
||||||
|
std::string("DISCL_FOREGROUND")));
|
||||||
|
pl.insert(std::make_pair(std::string("w32_keyboard"),
|
||||||
|
std::string("DISCL_NONEXCLUSIVE")));
|
||||||
|
#elif defined OIS_LINUX_PLATFORM
|
||||||
|
pl.insert(std::make_pair(std::string("x11_mouse_grab"),
|
||||||
|
std::string("false")));
|
||||||
|
pl.insert(std::make_pair(std::string("x11_mouse_hide"),
|
||||||
|
std::string("false")));
|
||||||
|
pl.insert(std::make_pair(std::string("x11_keyboard_grab"),
|
||||||
|
std::string("false")));
|
||||||
|
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
|
||||||
|
std::string("true")));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE_CC__
|
||||||
|
// Give the application window focus to receive input events
|
||||||
|
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
||||||
|
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||||
|
SetFrontProcess(&psn);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inputMgr = InputManager::createInputSystem( pl );
|
||||||
|
|
||||||
|
// Create all devices
|
||||||
|
keyboard = static_cast<Keyboard*>(inputMgr->createInputObject
|
||||||
|
( OISKeyboard, true ));
|
||||||
|
mouse = static_cast<Mouse*>(inputMgr->createInputObject
|
||||||
|
( OISMouse, true ));
|
||||||
|
|
||||||
|
// Set mouse region
|
||||||
|
const MouseState &ms = mouse->getMouseState();
|
||||||
|
ms.width = window->getWidth();
|
||||||
|
ms.height = window->getHeight();
|
||||||
|
|
||||||
|
// Set up the input listener
|
||||||
|
listener = new OISListener(*this);
|
||||||
|
keyboard-> setEventCallback(listener);
|
||||||
|
mouse-> setEventCallback(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
OISDriver::~OISDriver()
|
||||||
|
{
|
||||||
|
// Delete the listener object
|
||||||
|
if(listener)
|
||||||
|
delete listener;
|
||||||
|
|
||||||
|
if(inputMgr == NULL) return;
|
||||||
|
|
||||||
|
// Kill the input systems. This will reset input options such as key
|
||||||
|
// repeat rate.
|
||||||
|
inputMgr->destroyInputObject(keyboard);
|
||||||
|
inputMgr->destroyInputObject(mouse);
|
||||||
|
InputManager::destroyInputSystem(inputMgr);
|
||||||
|
inputMgr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OISDriver::capture()
|
||||||
|
{
|
||||||
|
// Capture keyboard and mouse events
|
||||||
|
keyboard->capture();
|
||||||
|
mouse->capture();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OISDriver::isDown(int index)
|
||||||
|
{
|
||||||
|
// TODO: Extend to mouse buttons as well
|
||||||
|
return keyboard->isKeyDown((OIS::KeyCode)index);
|
||||||
|
}
|
48
libs/mangle/input/servers/ois_driver.hpp
Normal file
48
libs/mangle/input/servers/ois_driver.hpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef MANGLE_INPUT_OIS_DRIVER_H
|
||||||
|
#define MANGLE_INPUT_OIS_DRIVER_H
|
||||||
|
|
||||||
|
#include "../driver.hpp"
|
||||||
|
|
||||||
|
namespace OIS
|
||||||
|
{
|
||||||
|
class InputManager;
|
||||||
|
class Mouse;
|
||||||
|
class Keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Ogre
|
||||||
|
{
|
||||||
|
class RenderWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
struct OISListener;
|
||||||
|
|
||||||
|
/** Input driver for OIS, the input manager typically used with
|
||||||
|
Ogre.
|
||||||
|
*/
|
||||||
|
struct OISDriver : Driver
|
||||||
|
{
|
||||||
|
/// If exclusive=true, then we capture mouse and keyboard from
|
||||||
|
/// the OS.
|
||||||
|
OISDriver(Ogre::RenderWindow *window, bool exclusive=true);
|
||||||
|
~OISDriver();
|
||||||
|
|
||||||
|
void capture();
|
||||||
|
bool isDown(int index);
|
||||||
|
/// Not currently supported.
|
||||||
|
void showMouse(bool) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
OIS::InputManager *inputMgr;
|
||||||
|
OIS::Mouse *mouse;
|
||||||
|
OIS::Keyboard *keyboard;
|
||||||
|
|
||||||
|
OISListener *listener;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
54
libs/mangle/input/servers/sdl_driver.cpp
Normal file
54
libs/mangle/input/servers/sdl_driver.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include "sdl_driver.hpp"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
using namespace Mangle::Input;
|
||||||
|
|
||||||
|
void SDLDriver::capture()
|
||||||
|
{
|
||||||
|
// Poll for events
|
||||||
|
SDL_Event evt;
|
||||||
|
while(SDL_PollEvent(&evt))
|
||||||
|
{
|
||||||
|
Event::Type type = Event::EV_Unknown;
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
|
switch(evt.type)
|
||||||
|
{
|
||||||
|
// For key events, send the keysym as the index.
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
type = Event::EV_KeyDown;
|
||||||
|
index = evt.key.keysym.sym;
|
||||||
|
break;
|
||||||
|
case SDL_KEYUP:
|
||||||
|
type = Event::EV_KeyUp;
|
||||||
|
index = evt.key.keysym.sym;
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
type = Event::EV_MouseMove;
|
||||||
|
break;
|
||||||
|
// Add more event types later
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass the event along, using -1 as index for unidentified
|
||||||
|
// event types.
|
||||||
|
makeEvent(type, index, &evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLDriver::isDown(int index)
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
Uint8 *keys = SDL_GetKeyState(&num);
|
||||||
|
assert(index >= 0 && index < num);
|
||||||
|
|
||||||
|
// The returned array from GetKeyState is indexed by the
|
||||||
|
// SDLK_KEYNAME enums and is just a list of bools. If the indexed
|
||||||
|
// value is true, the button is down.
|
||||||
|
return keys[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLDriver::showMouse(bool show)
|
||||||
|
{
|
||||||
|
SDL_ShowCursor(show?SDL_ENABLE:SDL_DISABLE);
|
||||||
|
}
|
27
libs/mangle/input/servers/sdl_driver.hpp
Normal file
27
libs/mangle/input/servers/sdl_driver.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef MANGLE_INPUT_SDL_DRIVER_H
|
||||||
|
#define MANGLE_INPUT_SDL_DRIVER_H
|
||||||
|
|
||||||
|
#include "../driver.hpp"
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Input
|
||||||
|
{
|
||||||
|
/** Input driver for SDL. As the input system of SDL is seldomly
|
||||||
|
used alone (most often along with the video system), it is
|
||||||
|
assumed that you do your own initialization and cleanup of SDL
|
||||||
|
before and after using this driver.
|
||||||
|
|
||||||
|
The Event.event() calls will be given the proper EV_ type, the
|
||||||
|
key index (for key up/down events), and a pointer to the full
|
||||||
|
SDL_Event structure.
|
||||||
|
*/
|
||||||
|
struct SDLDriver : Driver
|
||||||
|
{
|
||||||
|
void capture();
|
||||||
|
bool isDown(int index);
|
||||||
|
void showMouse(bool);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
2
libs/mangle/input/tests/.gitignore
vendored
Normal file
2
libs/mangle/input/tests/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*_test
|
||||||
|
ogre.cfg
|
15
libs/mangle/input/tests/Makefile
Normal file
15
libs/mangle/input/tests/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
GCC=g++ -Wall
|
||||||
|
|
||||||
|
all: sdl_driver_test ois_driver_test evtlist_test
|
||||||
|
|
||||||
|
sdl_driver_test: sdl_driver_test.cpp
|
||||||
|
$(GCC) $< ../servers/sdl_driver.cpp -o $@ -I/usr/include/SDL/ -lSDL
|
||||||
|
|
||||||
|
ois_driver_test: ois_driver_test.cpp
|
||||||
|
$(GCC) $< ../servers/ois_driver.cpp -o $@ -I/usr/local/include/OGRE/ -lOgreMain -lOIS -lboost_filesystem
|
||||||
|
|
||||||
|
evtlist_test: evtlist_test.cpp ../filters/eventlist.hpp ../event.hpp
|
||||||
|
$(GCC) $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *_test
|
35
libs/mangle/input/tests/common.cpp
Normal file
35
libs/mangle/input/tests/common.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include "../driver.hpp"
|
||||||
|
#include <unistd.h>
|
||||||
|
using namespace std;
|
||||||
|
using namespace Mangle::Input;
|
||||||
|
|
||||||
|
Driver *input;
|
||||||
|
|
||||||
|
struct MyCB : Event
|
||||||
|
{
|
||||||
|
void event(Event::Type type, int i, const void *p)
|
||||||
|
{
|
||||||
|
cout << "got event: type=" << type << " index=" << i << endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void mainLoop(int argc, int quitKey)
|
||||||
|
{
|
||||||
|
cout << "Hold the Q key to quit:\n";
|
||||||
|
input->setEvent(EventPtr(new MyCB));
|
||||||
|
while(!input->isDown(quitKey))
|
||||||
|
{
|
||||||
|
input->capture();
|
||||||
|
usleep(20000);
|
||||||
|
|
||||||
|
if(argc == 1)
|
||||||
|
{
|
||||||
|
cout << "You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete input;
|
||||||
|
cout << "\nBye bye!\n";
|
||||||
|
}
|
45
libs/mangle/input/tests/evtlist_test.cpp
Normal file
45
libs/mangle/input/tests/evtlist_test.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include "../filters/eventlist.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Mangle::Input;
|
||||||
|
|
||||||
|
struct MyEvent : Event
|
||||||
|
{
|
||||||
|
int ii;
|
||||||
|
MyEvent(int i) : ii(i) {}
|
||||||
|
|
||||||
|
void event(Event::Type type, int i, const void *p)
|
||||||
|
{
|
||||||
|
cout << " #" << ii << " got event: type=" << type << " index=" << i << endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EventList lst;
|
||||||
|
|
||||||
|
int iii=1;
|
||||||
|
void make(int flags)
|
||||||
|
{
|
||||||
|
lst.add(EventPtr(new MyEvent(iii++)), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(Event::Type type)
|
||||||
|
{
|
||||||
|
cout << "Sending type " << type << endl;
|
||||||
|
lst.event(type,0,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
make(Event::EV_ALL);
|
||||||
|
make(Event::EV_KeyDown);
|
||||||
|
make(Event::EV_KeyUp | Event::EV_MouseDown);
|
||||||
|
|
||||||
|
send(Event::EV_Unknown);
|
||||||
|
send(Event::EV_KeyDown);
|
||||||
|
send(Event::EV_KeyUp);
|
||||||
|
send(Event::EV_MouseDown);
|
||||||
|
|
||||||
|
cout << "Enough of that\n";
|
||||||
|
return 0;
|
||||||
|
}
|
51
libs/mangle/input/tests/ois_driver_test.cpp
Normal file
51
libs/mangle/input/tests/ois_driver_test.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#include "common.cpp"
|
||||||
|
|
||||||
|
#include "../servers/ois_driver.hpp"
|
||||||
|
#include <Ogre.h>
|
||||||
|
#include <OIS/OIS.h>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
bool isFile(const char *name)
|
||||||
|
{
|
||||||
|
boost::filesystem::path cfg_file_path(name);
|
||||||
|
return boost::filesystem::exists(cfg_file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Ogre;
|
||||||
|
using namespace OIS;
|
||||||
|
|
||||||
|
Root *root;
|
||||||
|
RenderWindow *window;
|
||||||
|
|
||||||
|
void setupOgre()
|
||||||
|
{
|
||||||
|
// Disable logging
|
||||||
|
new LogManager;
|
||||||
|
Log *log = LogManager::getSingleton().createLog("");
|
||||||
|
log->setDebugOutputEnabled(false);
|
||||||
|
|
||||||
|
bool useConfig = isFile("ogre.cfg");
|
||||||
|
|
||||||
|
// Set up Root
|
||||||
|
root = new Root("plugins.cfg", "ogre.cfg", "");
|
||||||
|
|
||||||
|
// Configure
|
||||||
|
if(!useConfig)
|
||||||
|
root->showConfigDialog();
|
||||||
|
else
|
||||||
|
root->restoreConfig();
|
||||||
|
|
||||||
|
// Initialize OGRE window
|
||||||
|
window = root->initialise(true, "test", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
setupOgre();
|
||||||
|
input = new OISDriver(window);
|
||||||
|
|
||||||
|
mainLoop(argc, KC_Q);
|
||||||
|
|
||||||
|
delete root;
|
||||||
|
return 0;
|
||||||
|
}
|
12
libs/mangle/input/tests/output/evtlist_test.out
Normal file
12
libs/mangle/input/tests/output/evtlist_test.out
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Sending type 1
|
||||||
|
#1 got event: type=1 index=0
|
||||||
|
Sending type 2
|
||||||
|
#1 got event: type=2 index=0
|
||||||
|
#2 got event: type=2 index=0
|
||||||
|
Sending type 4
|
||||||
|
#1 got event: type=4 index=0
|
||||||
|
#3 got event: type=4 index=0
|
||||||
|
Sending type 16
|
||||||
|
#1 got event: type=16 index=0
|
||||||
|
#3 got event: type=16 index=0
|
||||||
|
Enough of that
|
5
libs/mangle/input/tests/output/ois_driver_test.out
Normal file
5
libs/mangle/input/tests/output/ois_driver_test.out
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Hold the Q key to quit:
|
||||||
|
got event: type=8 index=-1
|
||||||
|
You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly
|
||||||
|
|
||||||
|
Bye bye!
|
5
libs/mangle/input/tests/output/sdl_driver_test.out
Normal file
5
libs/mangle/input/tests/output/sdl_driver_test.out
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Hold the Q key to quit:
|
||||||
|
got event: type=1 index=-1
|
||||||
|
You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly
|
||||||
|
|
||||||
|
Bye bye!
|
12
libs/mangle/input/tests/plugins.cfg
Normal file
12
libs/mangle/input/tests/plugins.cfg
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Defines plugins to load
|
||||||
|
|
||||||
|
# Define plugin folder
|
||||||
|
PluginFolder=/usr/local/lib/OGRE/
|
||||||
|
|
||||||
|
# Define plugins
|
||||||
|
Plugin=RenderSystem_GL
|
||||||
|
Plugin=Plugin_ParticleFX
|
||||||
|
Plugin=Plugin_OctreeSceneManager
|
||||||
|
# Plugin=Plugin_CgProgramManager
|
||||||
|
|
||||||
|
|
16
libs/mangle/input/tests/sdl_driver_test.cpp
Normal file
16
libs/mangle/input/tests/sdl_driver_test.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "common.cpp"
|
||||||
|
|
||||||
|
#include "../servers/sdl_driver.hpp"
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
SDL_SetVideoMode(640, 480, 0, SDL_SWSURFACE);
|
||||||
|
input = new SDLDriver();
|
||||||
|
|
||||||
|
mainLoop(argc, SDLK_q);
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
|
}
|
18
libs/mangle/input/tests/test.sh
Executable file
18
libs/mangle/input/tests/test.sh
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
make || exit
|
||||||
|
|
||||||
|
mkdir -p output
|
||||||
|
|
||||||
|
PROGS=*_test
|
||||||
|
|
||||||
|
for a in $PROGS; do
|
||||||
|
if [ -f "output/$a.out" ]; then
|
||||||
|
echo "Running $a:"
|
||||||
|
./$a | diff output/$a.out -
|
||||||
|
else
|
||||||
|
echo "Creating $a.out"
|
||||||
|
./$a > "output/$a.out"
|
||||||
|
git add "output/$a.out"
|
||||||
|
fi
|
||||||
|
done
|
63
libs/mangle/rend2d/driver.hpp
Normal file
63
libs/mangle/rend2d/driver.hpp
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#ifndef MANGLE_REND2D_DRIVER_H
|
||||||
|
#define MANGLE_REND2D_DRIVER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "sprite.hpp"
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Rend2D
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
The driver is the connection to the backend system that powers
|
||||||
|
2D sprite rendering. For example the backend could be SDL or
|
||||||
|
any other 2D-capable graphics library.
|
||||||
|
*/
|
||||||
|
struct Driver
|
||||||
|
{
|
||||||
|
/// Get the screen sprite
|
||||||
|
virtual Sprite *getScreen() = 0;
|
||||||
|
|
||||||
|
/// Sets the video mode.
|
||||||
|
virtual void setVideoMode(int width, int height, int bpp=32, bool fullscreen=false) = 0;
|
||||||
|
|
||||||
|
/** Update the screen. Until this function is called, none of
|
||||||
|
the changes written to the screen sprite will be visible.
|
||||||
|
*/
|
||||||
|
virtual void update() = 0;
|
||||||
|
|
||||||
|
/// Set the window title, as well as the title of the window
|
||||||
|
/// when "iconified"
|
||||||
|
virtual void setWindowTitle(const std::string &title,
|
||||||
|
const std::string &icon) = 0;
|
||||||
|
|
||||||
|
/// Set the window title
|
||||||
|
void setWindowTitle(const std::string &title) { setWindowTitle(title,title); }
|
||||||
|
|
||||||
|
/// Load sprite from an image file. Thows an exception on
|
||||||
|
/// failure.
|
||||||
|
virtual Sprite* loadImage(const std::string &file) = 0;
|
||||||
|
|
||||||
|
/// Load a sprite from an image file stored in memory. Throws
|
||||||
|
/// exception on failure.
|
||||||
|
virtual Sprite* loadImage(const void* data, size_t size) = 0;
|
||||||
|
|
||||||
|
/** @brief Set gamma value for all colors.
|
||||||
|
|
||||||
|
Note: Setting this in windowed mode will affect the ENTIRE
|
||||||
|
SCREEN!
|
||||||
|
*/
|
||||||
|
virtual void setGamma(float gamma) = 0;
|
||||||
|
|
||||||
|
/// Set gamma individually for red, green, blue
|
||||||
|
virtual void setGamma(float red, float green, float blue) = 0;
|
||||||
|
|
||||||
|
/// Get screen width
|
||||||
|
virtual int width() = 0;
|
||||||
|
|
||||||
|
/// Get screen height
|
||||||
|
virtual int height() = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
259
libs/mangle/rend2d/servers/sdl_driver.cpp
Normal file
259
libs/mangle/rend2d/servers/sdl_driver.cpp
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
#include "sdl_driver.hpp"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_image.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
using namespace Mangle::Rend2D;
|
||||||
|
|
||||||
|
const SpriteData *SDL_Sprite::lock()
|
||||||
|
{
|
||||||
|
// Make sure we aren't already locked
|
||||||
|
assert(!data.pixels);
|
||||||
|
|
||||||
|
// Lock the surface and set up the data structure
|
||||||
|
SDL_LockSurface(surface);
|
||||||
|
|
||||||
|
data.pixels = surface->pixels;
|
||||||
|
data.w = surface->w;
|
||||||
|
data.h = surface->h;
|
||||||
|
data.pitch = surface->pitch;
|
||||||
|
data.bypp = surface->format->BytesPerPixel;
|
||||||
|
|
||||||
|
return &data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL_Sprite::unlock()
|
||||||
|
{
|
||||||
|
if(data.pixels)
|
||||||
|
{
|
||||||
|
SDL_UnlockSurface(surface);
|
||||||
|
data.pixels = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a really crappy and slow implementation, only intended for
|
||||||
|
// testing purposes. Use lock/unlock for faster pixel drawing.
|
||||||
|
void SDL_Sprite::pixel(int x, int y, int color)
|
||||||
|
{
|
||||||
|
SDL_LockSurface(surface);
|
||||||
|
|
||||||
|
int bpp = surface->format->BytesPerPixel;
|
||||||
|
char *p = (char*)surface->pixels + y*surface->pitch + x*bpp;
|
||||||
|
|
||||||
|
switch(bpp)
|
||||||
|
{
|
||||||
|
case 1: *p = color; break;
|
||||||
|
case 3:
|
||||||
|
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
||||||
|
{
|
||||||
|
p[0] = (color >> 16) & 0xff;
|
||||||
|
p[1] = (color >> 8) & 0xff;
|
||||||
|
p[2] = color & 0xff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p[0] = color & 0xff;
|
||||||
|
p[1] = (color >> 8) & 0xff;
|
||||||
|
p[2] = (color >> 16) & 0xff;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*(int*)p = color;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SDL_UnlockSurface(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL_Sprite::draw(Sprite *s, // Must be SDL_Sprite
|
||||||
|
int x, int y, // Destination position
|
||||||
|
int sx, int sy, // Source position
|
||||||
|
int w, int h // Amount to draw. -1 means remainder.
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Get source surface
|
||||||
|
SDL_Sprite *other = dynamic_cast<SDL_Sprite*>(s);
|
||||||
|
assert(other != NULL);
|
||||||
|
SDL_Surface *img = other->getSurface();
|
||||||
|
|
||||||
|
// Check coordinate validity
|
||||||
|
assert(sx <= img->w && sy <= img->h);
|
||||||
|
assert(x <= surface->w && y <= surface->h);
|
||||||
|
assert(sx >= 0 && sy >= 0);
|
||||||
|
|
||||||
|
// Compute width and height if necessary
|
||||||
|
if(w == -1) w = img->w - sx;
|
||||||
|
if(h == -1) h = img->h - sy;
|
||||||
|
|
||||||
|
// Check them if they're valid
|
||||||
|
assert(w >= 0 && w <= img->w);
|
||||||
|
assert(h >= 0 && h <= img->h);
|
||||||
|
|
||||||
|
SDL_Rect dest;
|
||||||
|
dest.x = x;
|
||||||
|
dest.y = y;
|
||||||
|
dest.w = w;
|
||||||
|
dest.h = h;
|
||||||
|
|
||||||
|
SDL_Rect src;
|
||||||
|
src.x = sx;
|
||||||
|
src.y = sy;
|
||||||
|
src.w = w;
|
||||||
|
src.h = h;
|
||||||
|
|
||||||
|
// Do the Blitman
|
||||||
|
SDL_BlitSurface(img, &src, surface, &dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Sprite::SDL_Sprite(SDL_Surface *s, bool autoDelete)
|
||||||
|
: surface(s), autoDel(autoDelete)
|
||||||
|
{
|
||||||
|
assert(surface != NULL);
|
||||||
|
data.pixels = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Sprite::~SDL_Sprite()
|
||||||
|
{
|
||||||
|
if(autoDel)
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL_Sprite::fill(int value)
|
||||||
|
{
|
||||||
|
SDL_FillRect(surface, NULL, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_Sprite::width() { return surface->w; }
|
||||||
|
int SDL_Sprite::height() { return surface->h; }
|
||||||
|
|
||||||
|
SDLDriver::SDLDriver() : display(NULL), realDisp(NULL), softDouble(false)
|
||||||
|
{
|
||||||
|
if (SDL_InitSubSystem( SDL_INIT_VIDEO ) == -1)
|
||||||
|
throw std::runtime_error("Error initializing SDL video");
|
||||||
|
}
|
||||||
|
SDLDriver::~SDLDriver()
|
||||||
|
{
|
||||||
|
if(display) delete display;
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLDriver::setVideoMode(int width, int height, int bpp, bool fullscreen)
|
||||||
|
{
|
||||||
|
unsigned int flags;
|
||||||
|
|
||||||
|
if(display) delete display;
|
||||||
|
|
||||||
|
if (fullscreen)
|
||||||
|
// Assume fullscreen mode allows a double-bufferd hardware
|
||||||
|
// mode. We need more test code for this to be safe though.
|
||||||
|
flags = SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF;
|
||||||
|
else
|
||||||
|
flags = SDL_SWSURFACE;
|
||||||
|
|
||||||
|
// Create the surface and check it
|
||||||
|
realDisp = SDL_SetVideoMode(width, height, bpp, flags);
|
||||||
|
if(realDisp == NULL)
|
||||||
|
throw std::runtime_error("Failed setting SDL video mode");
|
||||||
|
|
||||||
|
// Code for software double buffering. I haven't found this to be
|
||||||
|
// any speed advantage at all in windowed mode (it's slower, as one
|
||||||
|
// would expect.) Not properly tested in fullscreen mode with
|
||||||
|
// hardware buffers, but it will probably only be an improvement if
|
||||||
|
// we do excessive writing (ie. write each pixel on average more
|
||||||
|
// than once) or try to read from the display buffer.
|
||||||
|
if(softDouble)
|
||||||
|
{
|
||||||
|
// Make a new surface with the same attributes as the real
|
||||||
|
// display surface.
|
||||||
|
SDL_Surface *back = SDL_DisplayFormat(realDisp);
|
||||||
|
assert(back != NULL);
|
||||||
|
|
||||||
|
// Create a sprite representing the double buffer
|
||||||
|
display = new SDL_Sprite(back);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create a sprite directly representing the display surface.
|
||||||
|
// The 'false' parameter means do not autodelete the screen
|
||||||
|
// surface upon exit (since SDL manages it)
|
||||||
|
display = new SDL_Sprite(realDisp, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the screen
|
||||||
|
void SDLDriver::update()
|
||||||
|
{
|
||||||
|
// Blit the soft double buffer onto the real display buffer
|
||||||
|
if(softDouble)
|
||||||
|
SDL_BlitSurface(display->getSurface(), NULL, realDisp, NULL );
|
||||||
|
|
||||||
|
if(realDisp)
|
||||||
|
SDL_Flip(realDisp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the window title, as well as the title of the window when
|
||||||
|
/// "iconified"
|
||||||
|
void SDLDriver::setWindowTitle(const std::string &title,
|
||||||
|
const std::string &icon)
|
||||||
|
{
|
||||||
|
SDL_WM_SetCaption( title.c_str(), icon.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the given surface to display format.
|
||||||
|
static SDL_Surface* convertImage(SDL_Surface* surf)
|
||||||
|
{
|
||||||
|
if(surf != NULL)
|
||||||
|
{
|
||||||
|
// Convert the image to the display buffer format, for faster
|
||||||
|
// blitting
|
||||||
|
SDL_Surface *surf2 = SDL_DisplayFormat(surf);
|
||||||
|
SDL_FreeSurface(surf);
|
||||||
|
surf = surf2;
|
||||||
|
}
|
||||||
|
return surf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load sprite from an image file, using SDL_image.
|
||||||
|
Sprite* SDLDriver::loadImage(const std::string &file)
|
||||||
|
{
|
||||||
|
SDL_Surface *surf = IMG_Load(file.c_str());
|
||||||
|
surf = convertImage(surf);
|
||||||
|
if(surf == NULL)
|
||||||
|
throw std::runtime_error("SDL failed to load image file '" + file + "'");
|
||||||
|
return spriteFromSDL(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load sprite from an SDL_RWops structure. autoFree determines
|
||||||
|
/// whether the RWops struct should be closed/freed after use.
|
||||||
|
Sprite* SDLDriver::loadImage(SDL_RWops *src, bool autoFree)
|
||||||
|
{
|
||||||
|
SDL_Surface *surf = IMG_Load_RW(src, autoFree);
|
||||||
|
surf = convertImage(surf);
|
||||||
|
if(surf == NULL)
|
||||||
|
throw std::runtime_error("SDL failed to load image");
|
||||||
|
return spriteFromSDL(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load a sprite from an image file stored in memory. Uses
|
||||||
|
/// SDL_image.
|
||||||
|
Sprite* SDLDriver::loadImage(const void* data, size_t size)
|
||||||
|
{
|
||||||
|
SDL_RWops *rw = SDL_RWFromConstMem(data, size);
|
||||||
|
return loadImage(rw, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLDriver::setGamma(float red, float green, float blue)
|
||||||
|
{
|
||||||
|
SDL_SetGamma(red,green,blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert an existing SDL surface into a sprite
|
||||||
|
Sprite* SDLDriver::spriteFromSDL(SDL_Surface *surf, bool autoFree)
|
||||||
|
{
|
||||||
|
assert(surf);
|
||||||
|
return new SDL_Sprite(surf, autoFree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLDriver::sleep(int ms) { SDL_Delay(ms); }
|
||||||
|
unsigned int SDLDriver::ticks() { return SDL_GetTicks(); }
|
125
libs/mangle/rend2d/servers/sdl_driver.hpp
Normal file
125
libs/mangle/rend2d/servers/sdl_driver.hpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
#ifndef MANGLE_DRAW2D_SDL_H
|
||||||
|
#define MANGLE_DRAW2D_SDL_H
|
||||||
|
|
||||||
|
#include "../driver.hpp"
|
||||||
|
|
||||||
|
// Predeclarations keep the streets safe at night
|
||||||
|
struct SDL_Surface;
|
||||||
|
struct SDL_RWops;
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Rend2D
|
||||||
|
{
|
||||||
|
/// SDL-implementation of Sprite
|
||||||
|
struct SDL_Sprite : Sprite
|
||||||
|
{
|
||||||
|
/** Draw a sprite in the given position. Can only draw other SDL
|
||||||
|
sprites.
|
||||||
|
*/
|
||||||
|
void draw(Sprite *s, // Must be SDL_Sprite
|
||||||
|
int x, int y, // Destination position
|
||||||
|
int sx=0, int sy=0, // Source position
|
||||||
|
int w=-1, int h=-1 // Amount to draw. -1 means remainder.
|
||||||
|
);
|
||||||
|
|
||||||
|
SDL_Sprite(SDL_Surface *s, bool autoDelete=true);
|
||||||
|
~SDL_Sprite();
|
||||||
|
|
||||||
|
// Information retrieval
|
||||||
|
int width();
|
||||||
|
int height();
|
||||||
|
SDL_Surface *getSurface() { return surface; }
|
||||||
|
|
||||||
|
// Fill with a given pixel value
|
||||||
|
void fill(int value);
|
||||||
|
|
||||||
|
// Set one pixel
|
||||||
|
void pixel(int x, int y, int value);
|
||||||
|
|
||||||
|
const SpriteData *lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The SDL surface
|
||||||
|
SDL_Surface* surface;
|
||||||
|
|
||||||
|
// Used for locking
|
||||||
|
SpriteData data;
|
||||||
|
|
||||||
|
// If true, delete this surface when the canvas is destructed
|
||||||
|
bool autoDel;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SDLDriver : public Driver
|
||||||
|
{
|
||||||
|
// The main display surface
|
||||||
|
SDL_Sprite *display;
|
||||||
|
|
||||||
|
// The actual display surface. May or may not be the same
|
||||||
|
// surface pointed to by 'display' above, depending on the
|
||||||
|
// softDouble flag.
|
||||||
|
SDL_Surface *realDisp;
|
||||||
|
|
||||||
|
// If true, we do software double buffering.
|
||||||
|
bool softDouble;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDLDriver();
|
||||||
|
~SDLDriver();
|
||||||
|
|
||||||
|
/// Sets the video mode. Will create the window if it is not
|
||||||
|
/// already set up. Note that for SDL, bpp=0 means use current
|
||||||
|
/// bpp.
|
||||||
|
void setVideoMode(int width, int height, int bpp=0, bool fullscreen=false);
|
||||||
|
|
||||||
|
/// Update the screen
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/// Set the window title, as well as the title of the window
|
||||||
|
/// when "iconified"
|
||||||
|
void setWindowTitle(const std::string &title,
|
||||||
|
const std::string &icon);
|
||||||
|
|
||||||
|
// Include overloads from our Glorious parent
|
||||||
|
using Driver::setWindowTitle;
|
||||||
|
|
||||||
|
/// Load sprite from an image file, using SDL_image.
|
||||||
|
Sprite* loadImage(const std::string &file);
|
||||||
|
|
||||||
|
/// Load sprite from an SDL_RWops structure. autoFree determines
|
||||||
|
/// whether the RWops struct should be closed/freed after use.
|
||||||
|
Sprite* loadImage(SDL_RWops *src, bool autoFree=false);
|
||||||
|
|
||||||
|
/// Load a sprite from an image file stored in memory. Uses
|
||||||
|
/// SDL_image.
|
||||||
|
Sprite* loadImage(const void* data, size_t size);
|
||||||
|
|
||||||
|
/// Set gamma value
|
||||||
|
void setGamma(float gamma) { setGamma(gamma,gamma,gamma); }
|
||||||
|
|
||||||
|
/// Set gamma individually for red, green, blue
|
||||||
|
void setGamma(float red, float green, float blue);
|
||||||
|
|
||||||
|
/// Convert an existing SDL surface into a sprite
|
||||||
|
Sprite* spriteFromSDL(SDL_Surface *surf, bool autoFree = true);
|
||||||
|
|
||||||
|
// Get width and height
|
||||||
|
int width() { return display ? display->width() : 0; }
|
||||||
|
int height() { return display ? display->height() : 0; }
|
||||||
|
|
||||||
|
/// Get the screen sprite
|
||||||
|
Sprite *getScreen() { return display; }
|
||||||
|
|
||||||
|
/// Not really a graphic-related function, but very
|
||||||
|
/// handly. Sleeps the given number of milliseconds using
|
||||||
|
/// SDL_Delay().
|
||||||
|
void sleep(int ms);
|
||||||
|
|
||||||
|
/// Get the number of ticks since SDL initialization, using
|
||||||
|
/// SDL_GetTicks().
|
||||||
|
unsigned int ticks();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
311
libs/mangle/rend2d/servers/sdl_gl_driver.cpp
Normal file
311
libs/mangle/rend2d/servers/sdl_gl_driver.cpp
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
#include "sdl_gl_driver.hpp"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_image.h>
|
||||||
|
#include <SDL_opengl.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
using namespace Mangle::Rend2D;
|
||||||
|
|
||||||
|
void SDLGL_Sprite::draw(Sprite *s, // Must be SDLGL_Sprite
|
||||||
|
int x, int y, // Destination position
|
||||||
|
int sx, int sy, // Source position
|
||||||
|
int w, int h // Amount to draw. -1 means remainder.
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Get source surface
|
||||||
|
SDLGL_Sprite *other = dynamic_cast<SDLGL_Sprite*>(s);
|
||||||
|
assert(other != NULL);
|
||||||
|
SDL_Surface *img = other->getSurface();
|
||||||
|
|
||||||
|
// Check coordinate validity
|
||||||
|
assert(sx <= img->w && sy <= img->h);
|
||||||
|
assert(x <= surface->w && y <= surface->h);
|
||||||
|
assert(sx >= 0 && sy >= 0);
|
||||||
|
|
||||||
|
// Compute width and height if necessary
|
||||||
|
if(w == -1) w = img->w - sx;
|
||||||
|
if(h == -1) h = img->h - sy;
|
||||||
|
|
||||||
|
// Check them if they're valid
|
||||||
|
assert(w >= 0 && w <= img->w);
|
||||||
|
assert(h >= 0 && h <= img->h);
|
||||||
|
|
||||||
|
SDL_Rect dest;
|
||||||
|
dest.x = x;
|
||||||
|
dest.y = y;
|
||||||
|
dest.w = w;
|
||||||
|
dest.h = h;
|
||||||
|
|
||||||
|
SDL_Rect src;
|
||||||
|
src.x = sx;
|
||||||
|
src.y = sy;
|
||||||
|
src.w = w;
|
||||||
|
src.h = h;
|
||||||
|
|
||||||
|
// Do the Blitman
|
||||||
|
SDL_BlitSurface(img, &src, surface, &dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDLGL_Sprite::SDLGL_Sprite(SDL_Surface *s, bool autoDelete)
|
||||||
|
: surface(s), autoDel(autoDelete)
|
||||||
|
{
|
||||||
|
assert(surface != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDLGL_Sprite::~SDLGL_Sprite()
|
||||||
|
{
|
||||||
|
if(autoDel)
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLGL_Sprite::fill(int value)
|
||||||
|
{
|
||||||
|
SDL_FillRect(surface, NULL, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDLGL_Sprite::width() { return surface->w; }
|
||||||
|
int SDLGL_Sprite::height() { return surface->h; }
|
||||||
|
|
||||||
|
SDLGLDriver::SDLGLDriver() : display(NULL), realDisp(NULL)
|
||||||
|
{
|
||||||
|
if (SDL_InitSubSystem( SDL_INIT_VIDEO ) == -1)
|
||||||
|
throw std::runtime_error("Error initializing SDL video");
|
||||||
|
}
|
||||||
|
SDLGLDriver::~SDLGLDriver()
|
||||||
|
{
|
||||||
|
if(display) delete display;
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Surface used for the screen. Since OpenGL surfaces must have sizes
|
||||||
|
// that are powers of 2, we have to "fake" the returned display size
|
||||||
|
// to match the screen, not the surface itself. If we don't use this,
|
||||||
|
// the client program will get confused about the actual size of our
|
||||||
|
// screen, thinking it is bigger than it is.
|
||||||
|
struct FakeSizeSprite : SDLGL_Sprite
|
||||||
|
{
|
||||||
|
int fakeW, fakeH;
|
||||||
|
|
||||||
|
FakeSizeSprite(SDL_Surface *s, int fw, int fh)
|
||||||
|
: SDLGL_Sprite(s), fakeW(fw), fakeH(fh)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int width() { return fakeW; }
|
||||||
|
int height() { return fakeH; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int makePow2(int num)
|
||||||
|
{
|
||||||
|
assert(num);
|
||||||
|
if((num & (num-1)) != 0)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
while(num)
|
||||||
|
{
|
||||||
|
num >>= 1;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
num = 1 << cnt;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLGLDriver::setVideoMode(int width, int height, int bpp, bool fullscreen)
|
||||||
|
{
|
||||||
|
unsigned int flags;
|
||||||
|
|
||||||
|
if(display) delete display;
|
||||||
|
|
||||||
|
flags = SDL_OPENGL;
|
||||||
|
|
||||||
|
if (fullscreen)
|
||||||
|
flags |= SDL_FULLSCREEN;
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1 );
|
||||||
|
|
||||||
|
// Create the surface and check it
|
||||||
|
screen = SDL_SetVideoMode(width, height, bpp, flags);
|
||||||
|
if(screen == NULL)
|
||||||
|
throw std::runtime_error("Failed setting SDL video mode");
|
||||||
|
|
||||||
|
// Expand width and height to be powers of 2
|
||||||
|
int width2 = makePow2(width);
|
||||||
|
int height2 = makePow2(height);
|
||||||
|
|
||||||
|
// Create a new SDL surface of this size
|
||||||
|
const SDL_PixelFormat& fmt = *(screen->format);
|
||||||
|
realDisp = SDL_CreateRGBSurface(SDL_SWSURFACE,width2,height2,
|
||||||
|
fmt.BitsPerPixel,
|
||||||
|
fmt.Rmask,fmt.Gmask,fmt.Bmask,fmt.Amask);
|
||||||
|
|
||||||
|
// Create a sprite directly representing the display surface. This
|
||||||
|
// allows the user to blit to it directly.
|
||||||
|
display = new FakeSizeSprite(realDisp, width, height);
|
||||||
|
|
||||||
|
// Set up the OpenGL format
|
||||||
|
nOfColors = fmt.BytesPerPixel;
|
||||||
|
|
||||||
|
if(nOfColors == 4)
|
||||||
|
{
|
||||||
|
if (fmt.Rmask == 0x000000ff)
|
||||||
|
texture_format = GL_RGBA;
|
||||||
|
else
|
||||||
|
texture_format = GL_BGRA;
|
||||||
|
}
|
||||||
|
else if(nOfColors == 3)
|
||||||
|
{
|
||||||
|
if (fmt.Rmask == 0x000000ff)
|
||||||
|
texture_format = GL_RGB;
|
||||||
|
else
|
||||||
|
texture_format = GL_BGR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assert(0 && "unsupported screen format");
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
// Have OpenGL generate a texture object handle for us
|
||||||
|
glGenTextures( 1, &texture );
|
||||||
|
|
||||||
|
// Bind the texture object
|
||||||
|
glBindTexture( GL_TEXTURE_2D, texture );
|
||||||
|
|
||||||
|
// Set the texture's stretching properties
|
||||||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLGLDriver::updateNoSwap()
|
||||||
|
{
|
||||||
|
if(!realDisp) return;
|
||||||
|
|
||||||
|
// Fist, set up the screen texture:
|
||||||
|
|
||||||
|
// Bind the texture object
|
||||||
|
glBindTexture( GL_TEXTURE_2D, texture );
|
||||||
|
|
||||||
|
// Edit the texture object's image data
|
||||||
|
glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, realDisp->w, realDisp->h, 0,
|
||||||
|
texture_format, GL_UNSIGNED_BYTE, realDisp->pixels );
|
||||||
|
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
// OpenGL barf. Set up the projection to match our screen
|
||||||
|
int vPort[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, vPort);
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glBegin( GL_QUADS );
|
||||||
|
|
||||||
|
// Needed to move the screen into the right place
|
||||||
|
int diff = screen->h - realDisp->h;
|
||||||
|
|
||||||
|
// Bottom-left vertex (corner)
|
||||||
|
glTexCoord2i( 0, 1 );
|
||||||
|
glVertex3f(0,diff,0);
|
||||||
|
|
||||||
|
// Bottom-right vertex (corner)
|
||||||
|
glTexCoord2i( 1, 1 );
|
||||||
|
glVertex3f( realDisp->w, diff, 0.f );
|
||||||
|
|
||||||
|
// Top-right vertex (corner)
|
||||||
|
glTexCoord2i( 1, 0 );
|
||||||
|
glVertex3f( realDisp->w, screen->h, 0.f );
|
||||||
|
|
||||||
|
// Top-left vertex (corner)
|
||||||
|
glTexCoord2i( 0, 0 );
|
||||||
|
glVertex3f( 0, screen->h, 0.f );
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPopMatrix();
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLGLDriver::swap()
|
||||||
|
{
|
||||||
|
SDL_GL_SwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLGLDriver::update()
|
||||||
|
{
|
||||||
|
updateNoSwap();
|
||||||
|
swap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the window title, as well as the title of the window when
|
||||||
|
/// "iconified"
|
||||||
|
void SDLGLDriver::setWindowTitle(const std::string &title,
|
||||||
|
const std::string &icon)
|
||||||
|
{
|
||||||
|
SDL_WM_SetCaption( title.c_str(), icon.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the given surface to display format.
|
||||||
|
static SDL_Surface* convertImage(SDL_Surface* surf)
|
||||||
|
{
|
||||||
|
if(surf != NULL)
|
||||||
|
{
|
||||||
|
// Convert the image to the display buffer format, for faster
|
||||||
|
// blitting
|
||||||
|
SDL_Surface *surf2 = SDL_DisplayFormat(surf);
|
||||||
|
SDL_FreeSurface(surf);
|
||||||
|
surf = surf2;
|
||||||
|
}
|
||||||
|
return surf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load sprite from an image file, using SDL_image.
|
||||||
|
Sprite* SDLGLDriver::loadImage(const std::string &file)
|
||||||
|
{
|
||||||
|
SDL_Surface *surf = IMG_Load(file.c_str());
|
||||||
|
surf = convertImage(surf);
|
||||||
|
if(surf == NULL)
|
||||||
|
throw std::runtime_error("SDL failed to load image file '" + file + "'");
|
||||||
|
return spriteFromSDL(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load sprite from an SDL_RWops structure. autoFree determines
|
||||||
|
/// whether the RWops struct should be closed/freed after use.
|
||||||
|
Sprite* SDLGLDriver::loadImage(SDL_RWops *src, bool autoFree)
|
||||||
|
{
|
||||||
|
SDL_Surface *surf = IMG_Load_RW(src, autoFree);
|
||||||
|
surf = convertImage(surf);
|
||||||
|
if(surf == NULL)
|
||||||
|
throw std::runtime_error("SDL failed to load image");
|
||||||
|
return spriteFromSDL(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load a sprite from an image file stored in memory. Uses
|
||||||
|
/// SDL_image.
|
||||||
|
Sprite* SDLGLDriver::loadImage(const void* data, size_t size)
|
||||||
|
{
|
||||||
|
SDL_RWops *rw = SDL_RWFromConstMem(data, size);
|
||||||
|
return loadImage(rw, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLGLDriver::setGamma(float red, float green, float blue)
|
||||||
|
{
|
||||||
|
SDL_SetGamma(red,green,blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert an existing SDL surface into a sprite
|
||||||
|
Sprite* SDLGLDriver::spriteFromSDL(SDL_Surface *surf, bool autoFree)
|
||||||
|
{
|
||||||
|
assert(surf);
|
||||||
|
return new SDLGL_Sprite(surf, autoFree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLGLDriver::sleep(int ms) { SDL_Delay(ms); }
|
||||||
|
unsigned int SDLGLDriver::ticks() { return SDL_GetTicks(); }
|
132
libs/mangle/rend2d/servers/sdl_gl_driver.hpp
Normal file
132
libs/mangle/rend2d/servers/sdl_gl_driver.hpp
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#ifndef MANGLE_DRAW2D_SDLGL_H
|
||||||
|
#define MANGLE_DRAW2D_SDLGL_H
|
||||||
|
|
||||||
|
/** This driver is similar to SDLDriver, except that it uses SDL on
|
||||||
|
top of OpenGL.
|
||||||
|
|
||||||
|
I've decided to make it a separate file instead of just adding
|
||||||
|
optional OpenGL support to the original, so that pure SDL users
|
||||||
|
don't have to add OpenGL as a dependency.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../driver.hpp"
|
||||||
|
|
||||||
|
// Predeclarations keep the streets safe at night
|
||||||
|
struct SDL_Surface;
|
||||||
|
struct SDL_RWops;
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Rend2D
|
||||||
|
{
|
||||||
|
/// SDL-implementation of Sprite
|
||||||
|
struct SDLGL_Sprite : Sprite
|
||||||
|
{
|
||||||
|
/** Draw a sprite in the given position. Can only draw other SDL
|
||||||
|
sprites.
|
||||||
|
*/
|
||||||
|
void draw(Sprite *s, // Must be SDLGL_Sprite
|
||||||
|
int x, int y, // Destination position
|
||||||
|
int sx=0, int sy=0, // Source position
|
||||||
|
int w=-1, int h=-1 // Amount to draw. -1 means remainder.
|
||||||
|
);
|
||||||
|
|
||||||
|
SDLGL_Sprite(SDL_Surface *s, bool autoDelete=true);
|
||||||
|
~SDLGL_Sprite();
|
||||||
|
|
||||||
|
// Information retrieval
|
||||||
|
virtual int width();
|
||||||
|
virtual int height();
|
||||||
|
SDL_Surface *getSurface() { return surface; }
|
||||||
|
|
||||||
|
// Fill with a given pixel value
|
||||||
|
void fill(int value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The SDL surface
|
||||||
|
SDL_Surface* surface;
|
||||||
|
|
||||||
|
// If true, delete this surface when the canvas is destructed
|
||||||
|
bool autoDel;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SDLGLDriver : public Driver
|
||||||
|
{
|
||||||
|
// The main display surface
|
||||||
|
SDLGL_Sprite *display;
|
||||||
|
|
||||||
|
// The screen surface. This is completely unused.
|
||||||
|
SDL_Surface *screen;
|
||||||
|
|
||||||
|
// The display surface and main GL texture. These are used when
|
||||||
|
// drawing the entire screen as one surface, as a drop-in
|
||||||
|
// replacement for SDLDriver.
|
||||||
|
SDL_Surface *realDisp;
|
||||||
|
unsigned int texture;
|
||||||
|
int nOfColors, texture_format;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDLGLDriver();
|
||||||
|
~SDLGLDriver();
|
||||||
|
|
||||||
|
/// Sets the video mode. Will create the window if it is not
|
||||||
|
/// already set up. Note that for SDL, bpp=0 means use current
|
||||||
|
/// bpp.
|
||||||
|
void setVideoMode(int width, int height, int bpp=0, bool fullscreen=false);
|
||||||
|
|
||||||
|
/// Update the screen
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/// Calls SDL_GL_SwapBuffers
|
||||||
|
void swap();
|
||||||
|
|
||||||
|
/// Draw surface to screen but do not call SDL_GL_SwapBuffers()
|
||||||
|
void updateNoSwap();
|
||||||
|
|
||||||
|
/// Set the window title, as well as the title of the window
|
||||||
|
/// when "iconified"
|
||||||
|
void setWindowTitle(const std::string &title,
|
||||||
|
const std::string &icon);
|
||||||
|
|
||||||
|
// Include overloads from our Glorious parent
|
||||||
|
using Driver::setWindowTitle;
|
||||||
|
|
||||||
|
/// Load sprite from an image file, using SDL_image.
|
||||||
|
Sprite* loadImage(const std::string &file);
|
||||||
|
|
||||||
|
/// Load sprite from an SDL_RWops structure. autoFree determines
|
||||||
|
/// whether the RWops struct should be closed/freed after use.
|
||||||
|
Sprite* loadImage(SDL_RWops *src, bool autoFree=false);
|
||||||
|
|
||||||
|
/// Load a sprite from an image file stored in memory. Uses
|
||||||
|
/// SDL_image.
|
||||||
|
Sprite* loadImage(const void* data, size_t size);
|
||||||
|
|
||||||
|
/// Set gamma value
|
||||||
|
void setGamma(float gamma) { setGamma(gamma,gamma,gamma); }
|
||||||
|
|
||||||
|
/// Set gamma individually for red, green, blue
|
||||||
|
void setGamma(float red, float green, float blue);
|
||||||
|
|
||||||
|
/// Convert an existing SDL surface into a sprite
|
||||||
|
Sprite* spriteFromSDL(SDL_Surface *surf, bool autoFree = true);
|
||||||
|
|
||||||
|
// Get width and height
|
||||||
|
int width() { return display ? display->width() : 0; }
|
||||||
|
int height() { return display ? display->height() : 0; }
|
||||||
|
|
||||||
|
/// Get the screen sprite
|
||||||
|
Sprite *getScreen() { return display; }
|
||||||
|
|
||||||
|
/// Not really a graphic-related function, but very
|
||||||
|
/// handly. Sleeps the given number of milliseconds using
|
||||||
|
/// SDL_Delay().
|
||||||
|
void sleep(int ms);
|
||||||
|
|
||||||
|
/// Get the number of ticks since SDL initialization, using
|
||||||
|
/// SDL_GetTicks().
|
||||||
|
unsigned int ticks();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
57
libs/mangle/rend2d/sprite.hpp
Normal file
57
libs/mangle/rend2d/sprite.hpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef MANGLE_REND2D_SPRITE_H
|
||||||
|
#define MANGLE_REND2D_SPRITE_H
|
||||||
|
|
||||||
|
namespace Mangle
|
||||||
|
{
|
||||||
|
namespace Rend2D
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
A pointer to sprite data for direct drawing. Only to be used
|
||||||
|
while the corresponding sprite is locked.
|
||||||
|
*/
|
||||||
|
struct SpriteData
|
||||||
|
{
|
||||||
|
void *pixels; // Pixel data
|
||||||
|
int w, h; // Width and height
|
||||||
|
int pitch, bypp; // Pitch (bytes) and bytes per pixel
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
A Sprite is either a bitmap to be drawn or an output of area
|
||||||
|
for blitting other bitmaps, or both. They are created by the
|
||||||
|
Driver.
|
||||||
|
*/
|
||||||
|
struct Sprite
|
||||||
|
{
|
||||||
|
/// Draw a sprite in the given position
|
||||||
|
virtual void draw(Sprite *s, // The sprite to draw
|
||||||
|
int x, int y, // Destination position
|
||||||
|
int sx=0, int sy=0, // Source position
|
||||||
|
int w=-1, int h=-1 // Amount to draw. -1 means remainder.
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
virtual ~Sprite() {}
|
||||||
|
|
||||||
|
// Information retrieval
|
||||||
|
virtual int width() = 0;
|
||||||
|
virtual int height() = 0;
|
||||||
|
|
||||||
|
/// Fill the sprite with the given pixel value. The pixel format
|
||||||
|
/// depends on the format of the sprite.
|
||||||
|
virtual void fill(int value) = 0;
|
||||||
|
|
||||||
|
/// Set one pixel value. The pixel format depends on the sprite
|
||||||
|
/// format. This is not expected to be fast, and in some
|
||||||
|
/// implementations may not work at all.
|
||||||
|
virtual void pixel(int x, int y, int value) {}
|
||||||
|
|
||||||
|
/// Lock sprite for direct drawing, and return a struct
|
||||||
|
/// containing the necessary pointer. When finished, unlock the
|
||||||
|
/// sprite with unlock(). May return NULL, if so then direct
|
||||||
|
/// drawing is not possible.
|
||||||
|
virtual const SpriteData *lock() { return NULL; }
|
||||||
|
virtual void unlock() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
1
libs/mangle/rend2d/tests/.gitignore
vendored
Normal file
1
libs/mangle/rend2d/tests/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*_test
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue