diff --git a/Bitstream Vera License.txt b/Bitstream Vera License.txt
new file mode 100644
index 0000000000..2b37cc1df2
--- /dev/null
+++ b/Bitstream Vera License.txt
@@ -0,0 +1,123 @@
+Bitstream Vera Fonts Copyright
+
+The fonts have a generous copyright, allowing derivative works (as
+long as "Bitstream" or "Vera" are not in the names), and full
+redistribution (so long as they are not *sold* by themselves). They
+can be be bundled, redistributed and sold with any software.
+
+The fonts are distributed under the following copyright:
+
+Copyright
+=========
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
+Vera is a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute
+the Font Software, including without limitation the rights to use,
+copy, merge, publish, distribute, and/or sell copies of the Font
+Software, and to permit persons to whom the Font Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Bitstream" or the word "Vera".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the
+"Bitstream Vera" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
+OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
+SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font
+Software without prior written authorization from the Gnome Foundation
+or Bitstream Inc., respectively. For further information, contact:
+fonts at gnome dot org.
+
+Copyright FAQ
+=============
+
+ 1. I don't understand the resale restriction... What gives?
+
+ Bitstream is giving away these fonts, but wishes to ensure its
+ competitors can't just drop the fonts as is into a font sale system
+ and sell them as is. It seems fair that if Bitstream can't make money
+ from the Bitstream Vera fonts, their competitors should not be able to
+ do so either. You can sell the fonts as part of any software package,
+ however.
+
+ 2. I want to package these fonts separately for distribution and
+ sale as part of a larger software package or system. Can I do so?
+
+ Yes. A RPM or Debian package is a "larger software package" to begin
+ with, and you aren't selling them independently by themselves.
+ See 1. above.
+
+ 3. Are derivative works allowed?
+ Yes!
+
+ 4. Can I change or add to the font(s)?
+ Yes, but you must change the name(s) of the font(s).
+
+ 5. Under what terms are derivative works allowed?
+
+ You must change the name(s) of the fonts. This is to ensure the
+ quality of the fonts, both to protect Bitstream and Gnome. We want to
+ ensure that if an application has opened a font specifically of these
+ names, it gets what it expects (though of course, using fontconfig,
+ substitutions could still could have occurred during font
+ opening). You must include the Bitstream copyright. Additional
+ copyrights can be added, as per copyright law. Happy Font Hacking!
+
+ 6. If I have improvements for Bitstream Vera, is it possible they might get
+ adopted in future versions?
+
+ Yes. The contract between the Gnome Foundation and Bitstream has
+ provisions for working with Bitstream to ensure quality additions to
+ the Bitstream Vera font family. Please contact us if you have such
+ additions. Note, that in general, we will want such additions for the
+ entire family, not just a single font, and that you'll have to keep
+ both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
+ glyphs to the font, they must be stylistically in keeping with Vera's
+ design. Vera cannot become a "ransom note" font. Jim Lyles will be
+ providing a document describing the design elements used in Vera, as a
+ guide and aid for people interested in contributing to Vera.
+
+ 7. I want to sell a software package that uses these fonts: Can I do so?
+
+ Sure. Bundle the fonts with your software and sell your software
+ with the fonts. That is the intent of the copyright.
+
+ 8. If applications have built the names "Bitstream Vera" into them,
+ can I override this somehow to use fonts of my choosing?
+
+ This depends on exact details of the software. Most open source
+ systems and software (e.g., Gnome, KDE, etc.) are now converting to
+ use fontconfig (see www.fontconfig.org) to handle font configuration,
+ selection and substitution; it has provisions for overriding font
+ names and subsituting alternatives. An example is provided by the
+ supplied local.conf file, which chooses the family Bitstream Vera for
+ "sans", "serif" and "monospace". Other software (e.g., the XFree86
+ core server) has other mechanisms for font substitution.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 08ce829f65..204efce9a6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,7 +30,6 @@ configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
# Sound source selection
-option(USE_AUDIERE "use Audiere for sound" OFF)
option(USE_FFMPEG "use ffmpeg for sound" OFF)
option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
@@ -120,52 +119,31 @@ set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/BulletShapeLoader.h
)
-# Sound setup
-if (USE_AUDIERE)
- set(MANGLE_SOUND_OUTPUT
- ${LIBDIR}/mangle/sound/sources/audiere_source.cpp
- ${LIBDIR}/mangle/sound/sources/sample_reader.cpp
- ${LIBDIR}/mangle/stream/clients/audiere_file.cpp)
- find_package(Audiere REQUIRED)
- set(SOUND_INPUT_INCLUDES ${AUDIERE_INCLUDE_DIR})
- set(SOUND_INPUT_LIBRARY ${AUDIERE_LIBRARY})
- set(SOUND_DEFINE -DOPENMW_USE_AUDIERE)
-endif (USE_AUDIERE)
-
-if (USE_FFMPEG)
- set(MANGLE_SOUND_OUTPUT
- ${LIBDIR}/mangle/sound/sources/ffmpeg_source.cpp)
- find_package(FFMPEG REQUIRED)
- set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIR})
- set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES})
- set(SOUND_DEFINE -DOPENMW_USE_FFMPEG)
-endif (USE_FFMPEG)
-
-if (USE_MPG123)
- set(MANGLE_SOUND_OUTPUT
- ${LIBDIR}/mangle/sound/sources/mpg123_source.cpp
- ${LIBDIR}/mangle/sound/sources/libsndfile.cpp
- ${LIBDIR}/mangle/sound/sources/sample_reader.cpp)
- find_package(MPG123 REQUIRED)
- find_package(SNDFILE REQUIRED)
- set(SOUND_INPUT_INCLUDES ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
- set(SOUND_INPUT_LIBRARY ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
- set(SOUND_DEFINE -DOPENMW_USE_MPG123)
-endif (USE_MPG123)
-
-set(OENGINE_SOUND
- # Mangle and OEngine sound files are sort of intertwined, so put
- # them together here
- ${LIBDIR}/openengine/sound/sndmanager.cpp
- ${LIBDIR}/mangle/sound/outputs/openal_out.cpp
- ${MANGLE_SOUND_OUTPUT}
-)
-set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_SOUND} ${OENGINE_BULLET})
+set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET})
source_group(libs\\openengine FILES ${OENGINE_ALL})
set(OPENMW_LIBS ${MANGLE_ALL} ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER)
+# Sound setup
+set(SOUND_INPUT_INCLUDES "")
+set(SOUND_INPUT_LIBRARY "")
+set(SOUND_DEFINE "")
+if (USE_FFMPEG)
+ find_package(FFMPEG REQUIRED)
+ set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIR})
+ set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES})
+ set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG)
+endif (USE_FFMPEG)
+
+if (USE_MPG123)
+ find_package(MPG123 REQUIRED)
+ find_package(SNDFILE REQUIRED)
+ set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
+ set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
+ set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
+endif (USE_MPG123)
+
# Platform specific
if (WIN32)
set(PLATFORM_INCLUDE_DIR "platform")
@@ -177,7 +155,6 @@ include_directories(${UUID_INCLUDE_DIR})
endif (WIN32)
if (MSVC10)
set(PLATFORM_INCLUDE_DIR "")
- add_definitions(-DMYGUI_DONT_REPLACE_NULLPTR)
endif()
if (APPLE)
@@ -186,7 +163,13 @@ endif (APPLE)
# Dependencies
+# Fix for not visible pthreads functions for linker with glibc 2.15
+if (UNIX AND NOT APPLE)
+find_package (Threads)
+endif()
+
find_package(OGRE REQUIRED)
+find_package(MyGUI REQUIRED)
find_package(Boost REQUIRED COMPONENTS system filesystem program_options thread)
find_package(OIS REQUIRED)
find_package(OpenAL REQUIRED)
@@ -203,14 +186,14 @@ include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS}
${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR}
- ${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/MyGUIEngine/include
- ${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/OgrePlatform/include
+ ${MYGUI_INCLUDE_DIRS}
+ ${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${UUID_INCLUDE_DIR}
${LIBDIR}
)
-link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
+link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
if(APPLE)
# List used Ogre plugins
@@ -220,14 +203,7 @@ if(APPLE)
"Plugin_ParticleFX")
endif(APPLE)
-add_subdirectory( extern/mygui_3.0.1 )
-
-# Make sure that certain libraries are used as static libraries
-# This is in effect turns off __declspec (dllexport) for windows
-# Each library will also need to be configured to build as a static lib
-
-# MyGUI: extern/mygui_3.0.0/
-add_definitions(-DMYGUI_STATIC)
+add_subdirectory( files/mygui )
# Specify build paths
@@ -322,7 +298,7 @@ if(DPKG_PROGRAM)
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher")
- SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libogre-1.7.3 (>= 1.7.3), libbullet0 (>= 2.77), libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
+ SET(CPACK_DEBIAN_PACKAGE_DEPENDS "nvidia-cg-toolkit (>= 2.1), libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
diff --git a/OFL.txt b/OFL.txt
new file mode 100644
index 0000000000..043e85e83b
--- /dev/null
+++ b/OFL.txt
@@ -0,0 +1,93 @@
+Copyright (c) 2010, 2011 Georg Duffner (http://www.georgduffner.at)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp
index 054cbf1414..c96fc2c7b6 100644
--- a/apps/launcher/datafilespage.cpp
+++ b/apps/launcher/datafilespage.cpp
@@ -222,7 +222,7 @@ void DataFilesPage::setupDataFiles()
QMessageBox msgBox;
msgBox.setWindowTitle("Error detecting Morrowind installation");
- msgBox.setIcon(QMessageBox::Critical);
+ msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Cancel);
msgBox.setText(tr("Could not find the Data Files location \
The directory containing the Data Files was not found. \
@@ -279,72 +279,79 @@ void DataFilesPage::setupDataFiles()
const Files::MultiDirCollection &esp = fileCollections.getCollection(".esp");
for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter) {
- ESMReader fileReader;
- QStringList availableMasters; // Will contain all found masters
- fileReader.setEncoding(variables["encoding"].as());
- fileReader.open(iter->second.string());
+ try {
+ ESMReader fileReader;
+ QStringList availableMasters; // Will contain all found masters
- // First we fill the availableMasters and the mMastersWidget
- ESMReader::MasterList mlist = fileReader.getMasters();
+ fileReader.setEncoding(variables["encoding"].as());
+ fileReader.open(iter->second.string());
- for (unsigned int i = 0; i < mlist.size(); ++i) {
- const QString currentMaster = QString::fromStdString(mlist[i].name);
- availableMasters.append(currentMaster);
+ // First we fill the availableMasters and the mMastersWidget
+ ESMReader::MasterList mlist = fileReader.getMasters();
- const QList itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
+ for (unsigned int i = 0; i < mlist.size(); ++i) {
+ const QString currentMaster = QString::fromStdString(mlist[i].name);
+ availableMasters.append(currentMaster);
- if (itemList.isEmpty()) { // Master is not yet in the widget
- mMastersWidget->insertRow(i);
+ const QList itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
- QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
- item->setForeground(Qt::red);
- item->setFlags(item->flags() & ~(Qt::ItemIsSelectable));
+ if (itemList.isEmpty()) { // Master is not yet in the widget
+ mMastersWidget->insertRow(i);
- mMastersWidget->setItem(i, 0, item);
+ QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
+ item->setForeground(Qt::red);
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable));
+
+ mMastersWidget->setItem(i, 0, item);
+ }
}
- }
- availableMasters.sort(); // Sort the masters alphabetically
+ availableMasters.sort(); // Sort the masters alphabetically
- // Now we put the current plugin in the mDataFilesModel under its masters
- QStandardItem *parent = new QStandardItem(availableMasters.join(","));
+ // Now we put the current plugin in the mDataFilesModel under its masters
+ QStandardItem *parent = new QStandardItem(availableMasters.join(","));
- QString fileName = QString::fromStdString(boost::filesystem::path (iter->second.filename()).string());
- QStandardItem *child = new QStandardItem(fileName);
+ QString fileName = QString::fromStdString(boost::filesystem::path (iter->second.filename()).string());
+ QStandardItem *child = new QStandardItem(fileName);
- // Tooltip information
- QString author = QString::fromStdString(fileReader.getAuthor());
- float version = fileReader.getFVer();
- QString description = QString::fromStdString(fileReader.getDesc());
+ // Tooltip information
+ QString author = QString::fromStdString(fileReader.getAuthor());
+ float version = fileReader.getFVer();
+ QString description = QString::fromStdString(fileReader.getDesc());
- // For the date created/modified
- QFileInfo fi(QString::fromStdString(iter->second.string()));
+ // For the date created/modified
+ QFileInfo fi(QString::fromStdString(iter->second.string()));
- QString toolTip= QString("Author: %1 \
- Version: %2 \
- Description: \
- %3 \
- Created on: %4 \
- Last modified: %5")
- .arg(author)
- .arg(version)
- .arg(description)
- .arg(fi.created().toString(Qt::TextDate))
- .arg(fi.lastModified().toString(Qt::TextDate));
+ QString toolTip= QString("Author: %1 \
+ Version: %2 \
+ Description: \
+ %3 \
+ Created on: %4 \
+ Last modified: %5")
+ .arg(author)
+ .arg(version)
+ .arg(description)
+ .arg(fi.created().toString(Qt::TextDate))
+ .arg(fi.lastModified().toString(Qt::TextDate));
- child->setToolTip(toolTip);
+ child->setToolTip(toolTip);
- const QList masterList = mDataFilesModel->findItems(availableMasters.join(","));
+ const QList masterList = mDataFilesModel->findItems(availableMasters.join(","));
- if (masterList.isEmpty()) { // Masters node not yet in the mDataFilesModel
- parent->appendRow(child);
- mDataFilesModel->appendRow(parent);
- } else {
- // Masters node exists, append current plugin
- foreach (QStandardItem *currentItem, masterList) {
- currentItem->appendRow(child);
+ if (masterList.isEmpty()) { // Masters node not yet in the mDataFilesModel
+ parent->appendRow(child);
+ mDataFilesModel->appendRow(parent);
+ } else {
+ // Masters node exists, append current plugin
+ foreach (QStandardItem *currentItem, masterList) {
+ currentItem->appendRow(child);
+ }
}
+
+ } catch(std::runtime_error &e) {
+ // An error occurred while reading the .esp
+ continue;
}
}
diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp
index 49c0bd960e..ef9cfa8519 100644
--- a/apps/launcher/maindialog.cpp
+++ b/apps/launcher/maindialog.cpp
@@ -45,9 +45,28 @@ MainDialog::MainDialog()
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
setMinimumSize(QSize(575, 575));
+ // Install the stylesheet font
+ QFile file;
+ QFontDatabase fontDatabase;
+
+ const QStringList fonts = fontDatabase.families();
+
+ // Check if the font is installed
+ if (!fonts.contains("EB Garamond")) {
+
+ QString font = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/mygui/EBGaramond-Regular.ttf").string());
+ file.setFileName(font);
+
+ if (!file.exists()) {
+ font = QString::fromStdString((mCfgMgr.getLocalPath() / "resources/mygui/EBGaramond-Regular.ttf").string());
+ }
+
+ fontDatabase.addApplicationFont(font);
+ }
+
// Load the stylesheet
QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string());
- QFile file(config);
+ file.setFileName(config);
if (!file.exists()) {
file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string()));
diff --git a/apps/launcher/resources/images/openmw-header.png b/apps/launcher/resources/images/openmw-header.png
index a168d4d2a8..a2ffab68b8 100644
Binary files a/apps/launcher/resources/images/openmw-header.png and b/apps/launcher/resources/images/openmw-header.png differ
diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt
index 6d33298dfe..6dc9382d03 100644
--- a/apps/openmw/CMakeLists.txt
+++ b/apps/openmw/CMakeLists.txt
@@ -14,7 +14,8 @@ set(GAME_HEADER
source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender
- renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface
+ renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
+ renderinginterface localmap
)
add_openmw_dir (mwinput
@@ -38,13 +39,13 @@ add_openmw_dir (mwscript
)
add_openmw_dir (mwsound
- soundmanager
+ soundmanager openal_output mpgsnd_decoder ffmpeg_decoder
)
add_openmw_dir (mwworld
refdata world physicssystem scene environment globals class action nullaction actionteleport
containerstore actiontalk actiontake manualref player cellfunctors
- cells localscripts customdata weather inventorystore
+ cells localscripts customdata weather inventorystore ptr
)
add_openmw_dir (mwclass
@@ -81,17 +82,22 @@ add_definitions(${SOUND_DEFINE})
target_link_libraries(openmw
${OGRE_LIBRARIES}
- ${OGRE_STATIC_PLUGINS}
+ ${OGRE_STATIC_PLUGINS}
${OIS_LIBRARIES}
${Boost_LIBRARIES}
${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY}
${BULLET_LIBRARIES}
+ ${MYGUI_LIBRARIES}
+ ${MYGUI_PLATFORM_LIBRARIES}
components
- MyGUIEngine
- MyGUIOgrePlatform
)
+# Fix for not visible pthreads functions for linker with glibc 2.15
+if (UNIX AND NOT APPLE)
+target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
+endif()
+
if(APPLE)
find_library(CARBON_FRAMEWORK Carbon)
target_link_libraries(openmw ${CARBON_FRAMEWORK})
diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp
index 89068ce533..5e49ae2f72 100644
--- a/apps/openmw/engine.cpp
+++ b/apps/openmw/engine.cpp
@@ -117,11 +117,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
// sound
if (mUseSound)
- {
- mEnvironment.mSoundManager->playPlaylist();
-
mEnvironment.mSoundManager->update (evt.timeSinceLastFrame);
- }
// update GUI
Ogre::RenderWindow* window = mOgre->getWindow();
@@ -337,10 +333,7 @@ void OMW::Engine::go()
mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"));
// Create sound system
- mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(),
- mOgre->getCamera(),
- mDataDirs,
- mUseSound, mFSStrict, mEnvironment);
+ mEnvironment.mSoundManager = new MWSound::SoundManager(mUseSound, mEnvironment);
// Create script system
mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full,
diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp
index dd57dfda07..50549f4a55 100644
--- a/apps/openmw/mwdialogue/dialoguemanager.cpp
+++ b/apps/openmw/mwdialogue/dialoguemanager.cpp
@@ -145,8 +145,6 @@ namespace MWDialogue
bool DialogueManager::functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice)
{
- bool isAChoice = false;//is there any choice in the filters?
- bool isFunction = false;
for (std::vector::const_iterator iter (info.selects.begin());
iter != info.selects.end(); ++iter)
{
@@ -154,7 +152,6 @@ namespace MWDialogue
char type = select.selectRule[1];
if(type == '1')
{
- isFunction = true;
char comp = select.selectRule[4];
std::string name = select.selectRule.substr (5);
std::string function = select.selectRule.substr(2,2);
@@ -193,7 +190,7 @@ namespace MWDialogue
break;
case 50://choice
- isAChoice = true;
+
if(choice)
{
if(!selectCompare(comp,mChoice,select.i)) return false;
@@ -516,7 +513,6 @@ namespace MWDialogue
return false;
// TODO check DATAstruct
-
for (std::vector::const_iterator iter (info.selects.begin());
iter != info.selects.end(); ++iter)
if (!isMatching (actor, *iter))
@@ -680,7 +676,8 @@ namespace MWDialogue
void DialogueManager::updateTopics()
{
std::list keywordList;
-
+ int choice = mChoice;
+ mChoice = -1;
actorKnownTopics.clear();
MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow();
ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list;
@@ -692,7 +689,7 @@ namespace MWDialogue
for (std::vector::const_iterator iter (it->second.mInfo.begin());
iter!=it->second.mInfo.end(); ++iter)
{
- if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,false))
+ if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true))
{
actorKnownTopics.push_back(it->first);
//does the player know the topic?
@@ -706,6 +703,7 @@ namespace MWDialogue
}
}
win->setKeywords(keywordList);
+ mChoice = choice;
}
void DialogueManager::keywordSelected(std::string keyword)
@@ -715,10 +713,9 @@ namespace MWDialogue
if(mDialogueMap.find(keyword) != mDialogueMap.end())
{
ESM::Dialogue ndialogue = mDialogueMap[keyword];
- std::vector::const_iterator iter;
if(ndialogue.type == ESM::Dialogue::Topic)
{
- for (iter = ndialogue.mInfo.begin();
+ for (std::vector::const_iterator iter = ndialogue.mInfo.begin();
iter!=ndialogue.mInfo.end(); ++iter)
{
if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true))
@@ -742,6 +739,7 @@ namespace MWDialogue
}
}
}
+
updateTopics();
}
diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp
index 93dde9f1bf..e9c15fab4a 100644
--- a/apps/openmw/mwgui/birth.cpp
+++ b/apps/openmw/mwgui/birth.cpp
@@ -21,18 +21,18 @@ BirthDialog::BirthDialog(WindowManager& parWindowManager)
getWidget(birthList, "BirthsignList");
birthList->setScrollVisible(true);
- birthList->eventListSelectAccept = MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
- birthList->eventListMouseItemActivate = MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
- birthList->eventListChangePosition = MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
+ birthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
+ birthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
+ birthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
- backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &BirthDialog::onBackClicked);
+ backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
- okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &BirthDialog::onOkClicked);
+ okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked);
updateBirths();
updateSpells();
@@ -100,7 +100,7 @@ void BirthDialog::onBackClicked(MyGUI::Widget* _sender)
eventBack();
}
-void BirthDialog::onSelectBirth(MyGUI::List* _sender, size_t _index)
+void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
@@ -188,7 +188,7 @@ void BirthDialog::updateSpells()
{
if (!categories[category].spells.empty())
{
- MyGUI::StaticTextPtr label = spellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label"));
+ MyGUI::TextBox* label = spellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label"));
label->setCaption(mWindowManager.getGameSettingString(categories[category].label, ""));
spellItems.push_back(label);
coord.top += lineHeight;
diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp
index a55a774a5b..b5f7db7749 100644
--- a/apps/openmw/mwgui/birth.hpp
+++ b/apps/openmw/mwgui/birth.hpp
@@ -32,7 +32,7 @@ namespace MWGui
void open();
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Back button clicked.\n
signature : void method()\n
@@ -40,7 +40,7 @@ namespace MWGui
EventHandle_Void eventBack;
protected:
- void onSelectBirth(MyGUI::List* _sender, size_t _index);
+ void onSelectBirth(MyGUI::ListBox* _sender, size_t _index);
void onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender);
@@ -49,9 +49,9 @@ namespace MWGui
void updateBirths();
void updateSpells();
- MyGUI::ListPtr birthList;
+ MyGUI::ListBox* birthList;
MyGUI::WidgetPtr spellArea;
- MyGUI::StaticImagePtr birthImage;
+ MyGUI::ImageBox* birthImage;
std::vector spellItems;
std::string currentBirthId;
diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp
index 1cb0593e73..ce5e744ccb 100644
--- a/apps/openmw/mwgui/charactercreation.cpp
+++ b/apps/openmw/mwgui/charactercreation.cpp
@@ -121,7 +121,7 @@ void CharacterCreation::spawnDialog(const char id)
mNameDialog->setTextLabel(mWM->getGameSettingString("sName", "Name"));
mNameDialog->setTextInput(mPlayerName);
mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen);
- mNameDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone);
+ mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone);
mNameDialog->open();
break;
@@ -131,8 +131,8 @@ void CharacterCreation::spawnDialog(const char id)
mRaceDialog = new RaceDialog(*mWM);
mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen);
mRaceDialog->setRaceId(mPlayerRaceId);
- mRaceDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone);
- mRaceDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack);
+ mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone);
+ mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack);
mRaceDialog->open();
break;
@@ -140,7 +140,7 @@ void CharacterCreation::spawnDialog(const char id)
if (mClassChoiceDialog)
mWM->removeDialog(mClassChoiceDialog);
mClassChoiceDialog = new ClassChoiceDialog(*mWM);
- mClassChoiceDialog->eventButtonSelected = MyGUI::newDelegate(this, &CharacterCreation::onClassChoice);
+ mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice);
mClassChoiceDialog->open();
break;
@@ -150,8 +150,8 @@ void CharacterCreation::spawnDialog(const char id)
mPickClassDialog = new PickClassDialog(*mWM);
mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen);
mPickClassDialog->setClassId(mPlayerClass.name);
- mPickClassDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone);
- mPickClassDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack);
+ mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone);
+ mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack);
mPickClassDialog->open();
break;
@@ -161,8 +161,8 @@ void CharacterCreation::spawnDialog(const char id)
mBirthSignDialog = new BirthDialog(*mWM);
mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen);
mBirthSignDialog->setBirthId(mPlayerBirthSignId);
- mBirthSignDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone);
- mBirthSignDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack);
+ mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone);
+ mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack);
mBirthSignDialog->open();
break;
@@ -170,8 +170,8 @@ void CharacterCreation::spawnDialog(const char id)
if (mCreateClassDialog)
mWM->removeDialog(mCreateClassDialog);
mCreateClassDialog = new CreateClassDialog(*mWM);
- mCreateClassDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
- mCreateClassDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
+ mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
+ mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
mCreateClassDialog->open();
break;
case GM_ClassGenerate:
@@ -212,9 +212,9 @@ void CharacterCreation::spawnDialog(const char id)
mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills);
}
- mReviewDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone);
- mReviewDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack);
- mReviewDialog->eventActivateDialog = MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog);
+ mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone);
+ mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack);
+ mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog);
mReviewDialog->open();
break;
}
@@ -559,8 +559,8 @@ void CharacterCreation::showClassQuestionDialog()
mWM->removeDialog(mGenerateClassResultDialog);
mGenerateClassResultDialog = new GenerateClassResultDialog(*mWM);
mGenerateClassResultDialog->setClassId(mGenerateClass);
- mGenerateClassResultDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack);
- mGenerateClassResultDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone);
+ mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack);
+ mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone);
mGenerateClassResultDialog->open();
return;
}
@@ -581,7 +581,7 @@ void CharacterCreation::showClassQuestionDialog()
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[1]);
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[2]);
mGenerateClassQuestionDialog->setButtons(buttons);
- mGenerateClassQuestionDialog->eventButtonSelected = MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen);
+ mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen);
mGenerateClassQuestionDialog->open();
}
diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp
index ad94f30b1e..75e534b42a 100644
--- a/apps/openmw/mwgui/class.cpp
+++ b/apps/openmw/mwgui/class.cpp
@@ -29,11 +29,11 @@ GenerateClassResultDialog::GenerateClassResultDialog(WindowManager& parWindowMan
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
- backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked);
+ backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
- okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked);
+ okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked);
}
void GenerateClassResultDialog::open()
@@ -96,20 +96,20 @@ PickClassDialog::PickClassDialog(WindowManager& parWindowManager)
getWidget(classList, "ClassList");
classList->setScrollVisible(true);
- classList->eventListSelectAccept = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
- classList->eventListMouseItemActivate = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
- classList->eventListChangePosition = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
+ classList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
+ classList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
+ classList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
getWidget(classImage, "ClassImage");
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
- backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &PickClassDialog::onBackClicked);
+ backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
- okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &PickClassDialog::onOkClicked);
+ okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked);
updateClasses();
updateStats();
@@ -177,7 +177,7 @@ void PickClassDialog::onBackClicked(MyGUI::Widget* _sender)
eventBack();
}
-void PickClassDialog::onSelectClass(MyGUI::List* _sender, size_t _index)
+void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
@@ -248,7 +248,7 @@ void PickClassDialog::updateStats()
/* InfoBoxDialog */
-void InfoBoxDialog::fitToText(MyGUI::StaticTextPtr widget)
+void InfoBoxDialog::fitToText(MyGUI::TextBox* widget)
{
MyGUI::IntCoord inner = widget->getTextRegion();
MyGUI::IntCoord outer = widget->getCoord();
@@ -267,7 +267,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin)
for (unsigned i = 0; i < count; ++i)
{
MyGUI::WidgetPtr child = widget->getChildAt(i);
- if (!child->isVisible())
+ if (!child->getVisible())
continue;
child->setPosition(child->getLeft(), pos);
@@ -322,7 +322,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons)
button->getSubWidgetText()->setWordWrap(true);
button->setCaption(text);
fitToText(button);
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked);
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked);
coord.top += button->getHeight();
this->buttons.push_back(button);
}
@@ -389,15 +389,15 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager)
setText("SpecializationT", mWindowManager.getGameSettingString("sChooseClassMenu1", "Specialization"));
getWidget(specializationName, "SpecializationName");
specializationName->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], ""));
- specializationName->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked);
+ specializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked);
setText("FavoriteAttributesT", mWindowManager.getGameSettingString("sChooseClassMenu2", "Favorite Attributes:"));
getWidget(favoriteAttribute0, "FavoriteAttribute0");
getWidget(favoriteAttribute1, "FavoriteAttribute1");
favoriteAttribute0->setWindowManager(&mWindowManager);
favoriteAttribute1->setWindowManager(&mWindowManager);
- favoriteAttribute0->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked);
- favoriteAttribute1->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked);
+ favoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked);
+ favoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked);
setText("MajorSkillT", mWindowManager.getGameSettingString("sSkillClassMajor", ""));
setText("MinorSkillT", mWindowManager.getGameSettingString("sSkillClassMinor", ""));
@@ -414,7 +414,7 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager)
for (std::vector::const_iterator it = skills.begin(); it != end; ++it)
{
(*it)->setWindowManager(&mWindowManager);
- (*it)->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked);
+ (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked);
}
setText("LabelT", mWindowManager.getGameSettingString("sName", ""));
@@ -426,15 +426,15 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager)
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr descriptionButton;
getWidget(descriptionButton, "DescriptionButton");
- descriptionButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked);
+ descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked);
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
- backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked);
+ backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
- okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked);
+ okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked);
// Set default skills, attributes
@@ -560,8 +560,8 @@ void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender)
if (specDialog)
delete specDialog;
specDialog = new SelectSpecializationDialog(mWindowManager);
- specDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
- specDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected);
+ specDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
+ specDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected);
specDialog->setVisible(true);
}
@@ -578,8 +578,8 @@ void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender)
delete attribDialog;
attribDialog = new SelectAttributeDialog(mWindowManager);
attribDialog->setAffectedWidget(_sender);
- attribDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
- attribDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected);
+ attribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
+ attribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected);
attribDialog->setVisible(true);
}
@@ -607,8 +607,8 @@ void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender)
delete skillDialog;
skillDialog = new SelectSkillDialog(mWindowManager);
skillDialog->setAffectedWidget(_sender);
- skillDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
- skillDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected);
+ skillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
+ skillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected);
skillDialog->setVisible(true);
}
@@ -638,7 +638,7 @@ void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender)
{
descDialog = new DescriptionDialog(mWindowManager);
descDialog->setTextInput(description);
- descDialog->eventDone = MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered);
+ descDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered);
descDialog->setVisible(true);
}
@@ -672,18 +672,18 @@ SelectSpecializationDialog::SelectSpecializationDialog(WindowManager& parWindowM
getWidget(specialization1, "Specialization1");
getWidget(specialization2, "Specialization2");
specialization0->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], ""));
- specialization0->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
+ specialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
specialization1->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Magic], ""));
- specialization1->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
+ specialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
specialization2->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Stealth], ""));
- specialization2->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
+ specialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
specializationId = ESM::Class::Combat;
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr cancelButton;
getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", ""));
- cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked);
+ cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked);
}
// widget controls
@@ -725,14 +725,14 @@ SelectAttributeDialog::SelectAttributeDialog(WindowManager& parWindowManager)
getWidget(attribute, std::string("Attribute").append(1, theIndex));
attribute->setWindowManager(&parWindowManager);
attribute->setAttributeId(ESM::Attribute::attributeIds[i]);
- attribute->eventClicked = MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked);
+ attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked);
}
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr cancelButton;
getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", ""));
- cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked);
+ cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked);
}
// widget controls
@@ -813,7 +813,7 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager)
{
skills[spec][i].widget->setWindowManager(&mWindowManager);
skills[spec][i].widget->setSkillId(skills[spec][i].skillId);
- skills[spec][i].widget->eventClicked = MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked);
+ skills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked);
}
}
@@ -821,7 +821,7 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager)
MyGUI::ButtonPtr cancelButton;
getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", ""));
- cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked);
+ cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked);
}
// widget controls
@@ -850,7 +850,7 @@ DescriptionDialog::DescriptionDialog(WindowManager& parWindowManager)
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
- okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked);
+ okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked);
okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", ""));
// Make sure the edit box has focus
diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp
index 5f1734b195..0e3348086d 100644
--- a/apps/openmw/mwgui/class.hpp
+++ b/apps/openmw/mwgui/class.hpp
@@ -31,7 +31,7 @@ namespace MWGui
int getChosenButton() const;
// Events
- typedef delegates::CDelegate1 EventHandle_Int;
+ typedef delegates::CMultiDelegate1 EventHandle_Int;
/** Event : Button was clicked.\n
signature : void method(MyGUI::WidgetPtr widget, int index)\n
@@ -43,11 +43,11 @@ namespace MWGui
private:
- void fitToText(MyGUI::StaticTextPtr widget);
+ void fitToText(MyGUI::TextBox* widget);
void layoutVertically(MyGUI::WidgetPtr widget, int margin);
int currentButton;
MyGUI::WidgetPtr textBox;
- MyGUI::StaticTextPtr text;
+ MyGUI::TextBox* text;
MyGUI::WidgetPtr buttonBar;
std::vector buttons;
};
@@ -78,7 +78,7 @@ namespace MWGui
void open();
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Back button clicked.\n
signature : void method()\n
@@ -90,8 +90,8 @@ namespace MWGui
void onBackClicked(MyGUI::Widget* _sender);
private:
- MyGUI::StaticImagePtr classImage;
- MyGUI::StaticTextPtr className;
+ MyGUI::ImageBox* classImage;
+ MyGUI::TextBox* className;
std::string currentClassId;
};
@@ -108,7 +108,7 @@ namespace MWGui
void open();
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Back button clicked.\n
signature : void method()\n
@@ -116,7 +116,7 @@ namespace MWGui
EventHandle_Void eventBack;
protected:
- void onSelectClass(MyGUI::List* _sender, size_t _index);
+ void onSelectClass(MyGUI::ListBox* _sender, size_t _index);
void onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender);
@@ -125,9 +125,9 @@ namespace MWGui
void updateClasses();
void updateStats();
- MyGUI::StaticImagePtr classImage;
- MyGUI::ListPtr classList;
- MyGUI::StaticTextPtr specializationName;
+ MyGUI::ImageBox* classImage;
+ MyGUI::ListBox* classList;
+ MyGUI::TextBox* specializationName;
Widgets::MWAttributePtr favoriteAttribute[2];
Widgets::MWSkillPtr majorSkill[5];
Widgets::MWSkillPtr minorSkill[5];
@@ -143,7 +143,7 @@ namespace MWGui
ESM::Class::Specialization getSpecializationId() const { return specializationId; }
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Cancel button clicked.\n
signature : void method()\n
@@ -160,7 +160,7 @@ namespace MWGui
void onCancelClicked(MyGUI::Widget* _sender);
private:
- MyGUI::WidgetPtr specialization0, specialization1, specialization2;
+ MyGUI::TextBox *specialization0, *specialization1, *specialization2;
ESM::Class::Specialization specializationId;
};
@@ -175,7 +175,7 @@ namespace MWGui
void setAffectedWidget(Widgets::MWAttributePtr widget) { affectedWidget = widget; }
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Cancel button clicked.\n
signature : void method()\n
@@ -207,7 +207,7 @@ namespace MWGui
void setAffectedWidget(Widgets::MWSkillPtr widget) { affectedWidget = widget; }
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Cancel button clicked.\n
signature : void method()\n
@@ -264,7 +264,7 @@ namespace MWGui
void open();
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Back button clicked.\n
signature : void method()\n
@@ -287,7 +287,7 @@ namespace MWGui
private:
MyGUI::EditPtr editName;
- MyGUI::WidgetPtr specializationName;
+ MyGUI::TextBox* specializationName;
Widgets::MWAttributePtr favoriteAttribute0, favoriteAttribute1;
Widgets::MWSkillPtr majorSkill[5];
Widgets::MWSkillPtr minorSkill[5];
diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp
index 3fd6e7892e..ac4f4a82a9 100644
--- a/apps/openmw/mwgui/console.cpp
+++ b/apps/openmw/mwgui/console.cpp
@@ -113,9 +113,9 @@ namespace MWGui
getWidget(history, "list_History");
// Set up the command line box
- command->eventEditSelectAccept =
+ command->eventEditSelectAccept +=
newDelegate(this, &Console::acceptCommand);
- command->eventKeyButtonPressed =
+ command->eventKeyButtonPressed +=
newDelegate(this, &Console::keyPress);
// Set up the log window
@@ -139,6 +139,9 @@ namespace MWGui
void Console::disable()
{
setVisible(false);
+ // Remove keyboard focus from the console input whenever the
+ // console is turned off
+ MyGUI::InputManager::getInstance().setKeyFocusWidget(NULL);
}
void Console::setFont(const std::string &fntName)
diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp
index cef47d074e..d6c4ce4e57 100644
--- a/apps/openmw/mwgui/dialogue.cpp
+++ b/apps/openmw/mwgui/dialogue.cpp
@@ -49,18 +49,25 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environm
//History view
getWidget(history, "History");
history->setOverflowToTheLeft(true);
- history->getClient()->eventMouseButtonClick = MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked);
history->setMaxTextLength(1000000);
+ Widget* eventbox;
+
+ //An EditBox cannot receive mouse click events, so we use an
+ //invisible widget on top of the editbox to receive them
+ /// \todo scrolling the dialogue history with the mouse wheel doesn't work using this solution
+ getWidget(eventbox, "EventBox");
+ eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked);
+
//Topics list
getWidget(topicsList, "TopicsList");
topicsList->setScrollVisible(true);
- //topicsList->eventListSelectAccept = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic);
- topicsList->eventListMouseItemActivate = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic);
- //topicsList->eventListChangePosition = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic);
+ //topicsList->eventListSelectAccept += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic);
+ topicsList->eventListMouseItemActivate += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic);
+ //topicsList->eventListChangePosition += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic);
MyGUI::ButtonPtr byeButton;
getWidget(byeButton, "ByeButton");
- byeButton->eventMouseButtonClick = MyGUI::newDelegate(this, &DialogueWindow::onByeClicked);
+ byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked);
getWidget(pDispositionBar, "Disposition");
getWidget(pDispositionText,"DispositionText");
@@ -68,11 +75,11 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environm
void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender)
{
- ISubWidgetText* t = history->getSubWidgetText();
+ ISubWidgetText* t = history->getClient()->getSubWidgetText();
if(t == nullptr)
return;
- const IntPoint& lastPressed = InputManager::getInstance().getLastLeftPressed();
+ const IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left);
size_t cursorPosition = t->getCursorPosition(lastPressed);
MyGUI::UString color = history->getColorAtPos(cursorPosition);
@@ -99,7 +106,7 @@ void DialogueWindow::onByeClicked(MyGUI::Widget* _sender)
mEnvironment.mDialogueManager->goodbyeSelected();
}
-void DialogueWindow::onSelectTopic(MyGUI::List* _sender, size_t _index)
+void DialogueWindow::onSelectTopic(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp
index 7dfd7bb7f4..b80a016cbe 100644
--- a/apps/openmw/mwgui/dialogue.hpp
+++ b/apps/openmw/mwgui/dialogue.hpp
@@ -21,7 +21,7 @@ namespace MWWorld
namespace MWGui
{
- class DialogeHistory;
+ class DialogueHistory;
using namespace MyGUI;
@@ -33,7 +33,7 @@ namespace MWGui
void open();
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Dialog finished, OK button clicked.\n
signature : void method()\n
@@ -49,7 +49,7 @@ namespace MWGui
void askQuestion(std::string question);
protected:
- void onSelectTopic(MyGUI::List* _sender, size_t _index);
+ void onSelectTopic(MyGUI::ListBox* _sender, size_t _index);
void onByeClicked(MyGUI::Widget* _sender);
void onHistoryClicked(MyGUI::Widget* _sender);
@@ -60,8 +60,8 @@ namespace MWGui
*/
std::string parseText(std::string text);
- DialogeHistory* history;
- MyGUI::ListPtr topicsList;
+ DialogueHistory* history;
+ MyGUI::ListBox* topicsList;
MyGUI::ProgressPtr pDispositionBar;
MyGUI::EditPtr pDispositionText;
std::map pTopicsText;// this map links keyword and "real" text.
diff --git a/apps/openmw/mwgui/dialogue_history.cpp b/apps/openmw/mwgui/dialogue_history.cpp
index ceb9045281..cd34ee119d 100644
--- a/apps/openmw/mwgui/dialogue_history.cpp
+++ b/apps/openmw/mwgui/dialogue_history.cpp
@@ -13,10 +13,10 @@
using namespace MWGui;
using namespace Widgets;
-UString DialogeHistory::getColorAtPos(size_t _pos)
+UString DialogueHistory::getColorAtPos(size_t _pos)
{
- UString colour = TextIterator::convertTagColour(mText->getTextColour());
- TextIterator iterator(mText->getCaption());
+ UString colour = TextIterator::convertTagColour(getTextColour());
+ TextIterator iterator(getCaption());
while(iterator.moveNext())
{
size_t pos = iterator.getPosition();
@@ -29,12 +29,12 @@ UString DialogeHistory::getColorAtPos(size_t _pos)
return colour;
}
-UString DialogeHistory::getColorTextAt(size_t _pos)
+UString DialogueHistory::getColorTextAt(size_t _pos)
{
bool breakOnNext = false;
- UString colour = TextIterator::convertTagColour(mText->getTextColour());
+ UString colour = TextIterator::convertTagColour(getTextColour());
UString colour2 = colour;
- TextIterator iterator(mText->getCaption());
+ TextIterator iterator(getCaption());
TextIterator col_start = iterator;
while(iterator.moveNext())
{
@@ -59,7 +59,7 @@ UString DialogeHistory::getColorTextAt(size_t _pos)
return "";
}
-void DialogeHistory::addDialogHeading(const UString& parText)
+void DialogueHistory::addDialogHeading(const UString& parText)
{
UString head("\n#D8C09A");
head.append(parText);
@@ -67,7 +67,7 @@ void DialogeHistory::addDialogHeading(const UString& parText)
addText(head);
}
-void DialogeHistory::addDialogText(const UString& parText)
+void DialogueHistory::addDialogText(const UString& parText)
{
addText(parText);
addText("\n");
diff --git a/apps/openmw/mwgui/dialogue_history.hpp b/apps/openmw/mwgui/dialogue_history.hpp
index ec41678e60..12a9c53e74 100644
--- a/apps/openmw/mwgui/dialogue_history.hpp
+++ b/apps/openmw/mwgui/dialogue_history.hpp
@@ -5,9 +5,9 @@
namespace MWGui
{
using namespace MyGUI;
- class DialogeHistory : public MyGUI::Edit
+ class DialogueHistory : public MyGUI::EditBox
{
- MYGUI_RTTI_DERIVED( DialogeHistory )
+ MYGUI_RTTI_DERIVED( DialogueHistory )
public:
Widget* getClient() { return mClient; }
UString getColorAtPos(size_t _pos);
diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp
index 5c9ef1f9b2..644bcbc04f 100644
--- a/apps/openmw/mwgui/journalwindow.cpp
+++ b/apps/openmw/mwgui/journalwindow.cpp
@@ -89,9 +89,9 @@ MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager)
getWidget(mLeftTextWidget, "LeftText");
getWidget(mRightTextWidget, "RightText");
getWidget(mPrevBtn, "PrevPageBTN");
- mPrevBtn->eventMouseButtonClick = MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyPrevPage);
+ mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyPrevPage);
getWidget(mNextBtn, "NextPageBTN");
- mNextBtn->eventMouseButtonClick = MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyNextPage);
+ mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyNextPage);
//MyGUI::ItemBox* list = new MyGUI::ItemBox();
//list->addItem("qaq","aqzazaz");
//mScrollerWidget->addChildItem(list);
@@ -111,7 +111,7 @@ MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager)
//displayLeftText(list.front());
MyGUI::WindowPtr t = static_cast(mMainWidget);
- t->eventWindowChangeCoord = MyGUI::newDelegate(this, &JournalWindow::onWindowResize);
+ t->eventWindowChangeCoord += MyGUI::newDelegate(this, &JournalWindow::onWindowResize);
}
void MWGui::JournalWindow::open()
diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp
index e664487634..4656c7a482 100644
--- a/apps/openmw/mwgui/journalwindow.hpp
+++ b/apps/openmw/mwgui/journalwindow.hpp
@@ -41,7 +41,7 @@ namespace MWGui
static const int lineHeight;
MyGUI::WidgetPtr skillAreaWidget, skillClientWidget;
- MyGUI::VScrollPtr skillScrollerWidget;
+ MyGUI::ScrollBar* skillScrollerWidget;
int lastPos, clientHeight;
MyGUI::EditPtr mLeftTextWidget;
MyGUI::EditPtr mRightTextWidget;
@@ -54,4 +54,4 @@ namespace MWGui
}
-#endif
\ No newline at end of file
+#endif
diff --git a/apps/openmw/mwgui/layouts.cpp b/apps/openmw/mwgui/layouts.cpp
index ebabc6faf1..dbd6154b7c 100644
--- a/apps/openmw/mwgui/layouts.cpp
+++ b/apps/openmw/mwgui/layouts.cpp
@@ -15,6 +15,22 @@ using namespace MWGui;
HUD::HUD(int width, int height, int fpsLevel)
: Layout("openmw_hud_layout.xml")
+ , health(NULL)
+ , magicka(NULL)
+ , stamina(NULL)
+ , weapImage(NULL)
+ , spellImage(NULL)
+ , weapStatus(NULL)
+ , spellStatus(NULL)
+ , effectBox(NULL)
+ , effect1(NULL)
+ , minimap(NULL)
+ , compass(NULL)
+ , crosshair(NULL)
+ , fpsbox(NULL)
+ , fpscounter(NULL)
+ , trianglecounter(NULL)
+ , batchcounter(NULL)
{
setCoord(0,0, width, height);
@@ -61,6 +77,8 @@ HUD::HUD(int width, int height, int fpsLevel)
setSpellIcon("icons\\s\\b_tx_s_rstor_health.dds");
setSpellStatus(65, 100);
setEffect("icons\\s\\tx_s_chameleon.dds");
+
+ LocalMapBase::init(minimap, this);
}
void HUD::setFPS(float fps)
@@ -142,3 +160,162 @@ void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& v
}
}
}
+
+void HUD::setPlayerDir(const float x, const float y)
+{
+ MyGUI::ISubWidget* main = compass->getSubWidgetMain();
+ MyGUI::RotatingSkin* rotatingSubskin = main->castType();
+ rotatingSubskin->setCenter(MyGUI::IntPoint(16,16));
+ float angle = std::atan2(x,y);
+ rotatingSubskin->setAngle(angle);
+}
+
+void HUD::setPlayerPos(const float x, const float y)
+{
+ MyGUI::IntSize size = minimap->getCanvasSize();
+ MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height);
+ MyGUI::IntCoord viewsize = minimap->getCoord();
+ MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top);
+
+ minimap->setViewOffset(pos);
+ compass->setPosition(MyGUI::IntPoint(x*512-16, y*512-16));
+}
+
+MapWindow::MapWindow()
+ : Layout("openmw_map_window_layout.xml"), mGlobal(false)
+{
+ setCoord(500,0,320,300);
+ setText("WorldButton", "World");
+ setImage("Compass", "textures\\compass.dds");
+
+ // Obviously you should override this later on
+ setCellName("No Cell Loaded");
+
+ getWidget(mLocalMap, "LocalMap");
+ getWidget(mGlobalMap, "GlobalMap");
+ getWidget(mPlayerArrow, "Compass");
+
+ getWidget(mButton, "WorldButton");
+ mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked);
+
+ MyGUI::Button* eventbox;
+ getWidget(eventbox, "EventBox");
+ eventbox->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
+ eventbox->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
+
+ LocalMapBase::init(mLocalMap, this);
+}
+
+void MapWindow::setVisible(bool b)
+{
+ mMainWidget->setVisible(b);
+ if (b)
+ mVisible = true;
+ else
+ mVisible = false;
+}
+
+void MapWindow::setCellName(const std::string& cellName)
+{
+ static_cast(mMainWidget)->setCaption(cellName);
+ adjustWindowCaption();
+}
+
+void MapWindow::setPlayerPos(const float x, const float y)
+{
+ if (mGlobal || mVisible) return;
+ MyGUI::IntSize size = mLocalMap->getCanvasSize();
+ MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height);
+ MyGUI::IntCoord viewsize = mLocalMap->getCoord();
+ MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top);
+ mLocalMap->setViewOffset(pos);
+
+ mPlayerArrow->setPosition(MyGUI::IntPoint(x*512-16, y*512-16));
+}
+
+void MapWindow::setPlayerDir(const float x, const float y)
+{
+ if (!mVisible) return;
+ MyGUI::ISubWidget* main = mPlayerArrow->getSubWidgetMain();
+ MyGUI::RotatingSkin* rotatingSubskin = main->castType();
+ rotatingSubskin->setCenter(MyGUI::IntPoint(16,16));
+ float angle = std::atan2(x,y);
+ rotatingSubskin->setAngle(angle);
+}
+
+void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
+{
+ if (_id!=MyGUI::MouseButton::Left) return;
+ if (!mGlobal)
+ mLastDragPos = MyGUI::IntPoint(_left, _top);
+}
+
+void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
+{
+ if (_id!=MyGUI::MouseButton::Left) return;
+
+ if (!mGlobal)
+ {
+ MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos;
+ mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff );
+
+ mLastDragPos = MyGUI::IntPoint(_left, _top);
+ }
+}
+
+void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender)
+{
+ mGlobal = !mGlobal;
+ mGlobalMap->setVisible(mGlobal);
+ mLocalMap->setVisible(!mGlobal);
+
+ mButton->setCaption( mGlobal ? "Local" : "World" );
+}
+
+void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout)
+{
+ mLocalMap = widget;
+ mLayout = layout;
+}
+
+void LocalMapBase::setCellPrefix(const std::string& prefix)
+{
+ mPrefix = prefix;
+ mChanged = true;
+}
+
+void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
+{
+ if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell
+ for (int mx=0; mx<3; ++mx)
+ {
+ for (int my=0; my<3; ++my)
+ {
+ std::string name = "Map_" + boost::lexical_cast(mx) + "_"
+ + boost::lexical_cast(my);
+
+ std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_"
+ + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1)));
+
+ MyGUI::ImageBox* box;
+ mLayout->getWidget(box, name);
+ MyGUI::ImageBox* fog;
+ mLayout->getWidget(fog, name+"_fog");
+
+ if (MyGUI::RenderManager::getInstance().getTexture(image) != 0)
+ box->setImageTexture(image);
+ else
+ box->setImageTexture("black.png");
+
+ if (MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0)
+ fog->setImageTexture(image+"_fog");
+ else
+ fog->setImageTexture("black.png");
+ }
+ }
+ mInterior = interior;
+ mCurX = x;
+ mCurY = y;
+ mChanged = false;
+}
+
diff --git a/apps/openmw/mwgui/layouts.hpp b/apps/openmw/mwgui/layouts.hpp
index 9917dcdccc..8d9a41a229 100644
--- a/apps/openmw/mwgui/layouts.hpp
+++ b/apps/openmw/mwgui/layouts.hpp
@@ -14,6 +14,8 @@
#include "../mwmechanics/stat.hpp"
#include "window_base.hpp"
+#include
+
/*
This file contains classes corresponding to window layouts
defined in resources/mygui/ *.xml.
@@ -29,7 +31,25 @@
namespace MWGui
{
- class HUD : public OEngine::GUI::Layout
+ class LocalMapBase
+ {
+ public:
+ void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout);
+
+ void setCellPrefix(const std::string& prefix);
+ void setActiveCell(const int x, const int y, bool interior=false);
+
+ protected:
+ int mCurX, mCurY;
+ bool mInterior;
+ MyGUI::ScrollView* mLocalMap;
+ std::string mPrefix;
+ bool mChanged;
+
+ OEngine::GUI::Layout* mLayout;
+ };
+
+ class HUD : public OEngine::GUI::Layout, public LocalMapBase
{
public:
HUD(int width, int height, int fpsLevel);
@@ -43,40 +63,45 @@ namespace MWGui
void setFPS(float fps);
void setTriangleCount(size_t count);
void setBatchCount(size_t count);
+ void setPlayerDir(const float x, const float y);
+ void setPlayerPos(const float x, const float y);
MyGUI::ProgressPtr health, magicka, stamina;
- MyGUI::StaticImagePtr weapImage, spellImage;
+ MyGUI::ImageBox *weapImage, *spellImage;
MyGUI::ProgressPtr weapStatus, spellStatus;
MyGUI::WidgetPtr effectBox;
- MyGUI::StaticImagePtr effect1;
- MyGUI::StaticImagePtr minimap;
- MyGUI::StaticImagePtr compass;
- MyGUI::StaticImagePtr crosshair;
+ MyGUI::ImageBox* effect1;
+ MyGUI::ScrollView* minimap;
+ MyGUI::ImageBox* compass;
+ MyGUI::ImageBox* crosshair;
MyGUI::WidgetPtr fpsbox;
- MyGUI::StaticTextPtr fpscounter;
- MyGUI::StaticTextPtr trianglecounter;
- MyGUI::StaticTextPtr batchcounter;
+ MyGUI::TextBox* fpscounter;
+ MyGUI::TextBox* trianglecounter;
+ MyGUI::TextBox* batchcounter;
};
- class MapWindow : public OEngine::GUI::Layout
+ class MapWindow : public OEngine::GUI::Layout, public LocalMapBase
{
public:
- MapWindow()
- : Layout("openmw_map_window_layout.xml")
- {
- setCoord(500,0,320,300);
- setText("WorldButton", "World");
- setImage("Compass", "compass.dds");
+ MapWindow();
- // Obviously you should override this later on
- setCellName("No Cell Loaded");
- }
+ void setVisible(bool b);
+ void setPlayerPos(const float x, const float y);
+ void setPlayerDir(const float x, const float y);
+ void setCellName(const std::string& cellName);
+
+ private:
+ void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
+ void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
+ void onWorldButtonClicked(MyGUI::Widget* _sender);
- void setCellName(const std::string& cellName)
- {
- mMainWidget->setCaption(cellName);
- }
+ MyGUI::ScrollView* mGlobalMap;
+ MyGUI::ImageBox* mPlayerArrow;
+ MyGUI::Button* mButton;
+ MyGUI::IntPoint mLastDragPos;
+ bool mVisible;
+ bool mGlobal;
};
class MainMenu : public OEngine::GUI::Layout
@@ -127,7 +152,7 @@ namespace MWGui
getWidget(avatar, "Avatar");
// Adjust armor rating text to bottom of avatar widget
- MyGUI::StaticTextPtr armor_rating;
+ MyGUI::TextBox* armor_rating;
getWidget(armor_rating, "ArmorRating");
armor_rating->setCaption("Armor: 11");
MyGUI::IntCoord coord = armor_rating->getCoord();
@@ -165,7 +190,7 @@ namespace MWGui
last_x += coord.width + margin;
button_pt->setCoord(coord);
- button_pt->eventMouseButtonClick = MyGUI::newDelegate(this, &InventoryWindow::onCategorySelected);
+ button_pt->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onCategorySelected);
}
}
diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp
index f0745bbbec..c103bcb8b8 100644
--- a/apps/openmw/mwgui/messagebox.cpp
+++ b/apps/openmw/mwgui/messagebox.cpp
@@ -19,7 +19,7 @@ void MessageBoxManager::onFrame (float frameDuration)
if(it->current >= it->max)
{
it->messageBox->mMarkedToDelete = true;
-
+
if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one
{
// collect all with mMarkedToDelete and delete them.
@@ -47,7 +47,7 @@ void MessageBoxManager::onFrame (float frameDuration)
it++;
}
}
-
+
if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) {
delete mInterMessageBoxe;
mInterMessageBoxe = NULL;
@@ -57,20 +57,18 @@ void MessageBoxManager::onFrame (float frameDuration)
void MessageBoxManager::createMessageBox (const std::string& message)
{
- std::cout << "MessageBox: " << message << std::endl;
-
MessageBox *box = new MessageBox(*this, message);
-
+
removeMessageBox(message.length()*mMessageBoxSpeed, box);
-
+
mMessageBoxes.push_back(box);
std::vector::iterator it;
-
+
if(mMessageBoxes.size() > 3) {
delete *mMessageBoxes.begin();
mMessageBoxes.erase(mMessageBoxes.begin());
}
-
+
int height = 0;
for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it)
{
@@ -88,9 +86,9 @@ bool MessageBoxManager::createInteractiveMessageBox (const std::string& message,
std::cout << "interactive MessageBox: " << message << " - ";
std::copy (buttons.begin(), buttons.end(), std::ostream_iterator (std::cout, ", "));
std::cout << std::endl;
-
+
mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons);
-
+
return true;
}
@@ -105,7 +103,7 @@ void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox)
timer.current = 0;
timer.max = time;
timer.messageBox = msgbox;
-
+
mTimers.insert(mTimers.end(), timer);
}
@@ -152,25 +150,26 @@ MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::strin
mBottomPadding = 20;
mNextBoxPadding = 20;
mMarkedToDelete = false;
-
+
getWidget(mMessageWidget, "message");
-
+
mMessageWidget->setOverflowToTheLeft(true);
mMessageWidget->addText(cMessage);
-
+
MyGUI::IntSize size;
size.width = mFixedWidth;
size.height = 100; // dummy
-
+
MyGUI::IntCoord coord;
coord.left = 10; // dummy
coord.top = 10; // dummy
mMessageWidget->setSize(size);
-
- MyGUI::IntSize textSize = mMessageWidget->_getTextSize();
+
+ MyGUI::IntSize textSize = mMessageWidget->getTextSize();
+
size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box
-
+
mMainWidget->setSize(size);
size.width -= 15; // this is to center the text (see messagebox_layout.xml, Widget type="Edit" position="-2 -3 0 0")
mMessageWidget->setSize(size);
@@ -178,15 +177,15 @@ MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::strin
void MessageBox::update (int height)
{
- MyGUI::IntSize gameWindowSize = mMessageBoxManager.mWindowManager->getGui()->getViewSize();
+ MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
MyGUI::IntCoord coord;
coord.left = (gameWindowSize.width - mFixedWidth)/2;
coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding);
-
+
MyGUI::IntSize size;
size.width = mFixedWidth;
size.height = mHeight;
-
+
mMainWidget->setCoord(coord);
mMainWidget->setSize(size);
mMainWidget->setVisible(true);
@@ -211,26 +210,26 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan
int buttonTopPadding = 5; // ^-- if vertical
int buttonPadding = 5; // padding between button label and button itself
int buttonMainPadding = 10; // padding between buttons and bottom of the main widget
-
+
mMarkedToDelete = false;
-
-
+
+
getWidget(mMessageWidget, "message");
getWidget(mButtonsWidget, "buttons");
-
+
mMessageWidget->setOverflowToTheLeft(true);
mMessageWidget->addText(message);
-
- MyGUI::IntSize textSize = mMessageWidget->_getTextSize();
-
- MyGUI::IntSize gameWindowSize = mMessageBoxManager.mWindowManager->getGui()->getViewSize();
-
+
+ MyGUI::IntSize textSize = mMessageWidget->getTextSize();
+
+ MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
+
int biggestButtonWidth = 0;
int buttonWidth = 0;
int buttonsWidth = 0;
int buttonHeight = 0;
MyGUI::IntCoord dummyCoord(0, 0, 0, 0);
-
+
std::vector::const_iterator it;
for(it = buttons.begin(); it != buttons.end(); ++it)
{
@@ -240,28 +239,28 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan
dummyCoord,
MyGUI::Align::Default);
button->setCaption(*it);
-
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed);
-
+
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed);
+
mButtons.push_back(button);
-
- buttonWidth = button->_getTextSize().width + 2*buttonPadding + buttonLeftPadding;
+
+ buttonWidth = button->getTextSize().width + 2*buttonPadding + buttonLeftPadding;
buttonsWidth += buttonWidth;
- buttonHeight = button->_getTextSize().height + 2*buttonPadding + buttonTopPadding;
-
+ buttonHeight = button->getTextSize().height + 2*buttonPadding + buttonTopPadding;
+
if(buttonWidth > biggestButtonWidth)
{
biggestButtonWidth = buttonWidth;
}
}
buttonsWidth += buttonLeftPadding;
-
+
MyGUI::IntSize mainWidgetSize;
if(buttonsWidth < fixedWidth)
{
// on one line
std::cout << "on one line" << std::endl;
-
+
if(textSize.width + 2*textPadding < buttonsWidth)
{
std::cout << "width = buttonsWidth" << std::endl;
@@ -272,48 +271,48 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan
mainWidgetSize.width = textSize.width + 3*textPadding;
}
mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding;
-
+
MyGUI::IntCoord absCoord;
absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2;
absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2;
-
+
std::cout << "width " << mainWidgetSize.width << " height " << mainWidgetSize.height << std::endl;
std::cout << "left " << absCoord.left << " top " << absCoord.top << std::endl;
-
+
mMainWidget->setCoord(absCoord);
mMainWidget->setSize(mainWidgetSize);
-
-
+
+
MyGUI::IntCoord messageWidgetCoord;
messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2;
messageWidgetCoord.top = textPadding;
mMessageWidget->setCoord(messageWidgetCoord);
-
+
mMessageWidget->setSize(textSize);
-
+
MyGUI::IntCoord buttonCord;
MyGUI::IntSize buttonSize(0, buttonHeight);
int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding;
-
+
std::vector::const_iterator button;
for(button = mButtons.begin(); button != mButtons.end(); ++button)
{
buttonCord.left = left;
buttonCord.top = textSize.height + textButtonPadding;
-
- buttonSize.width = (*button)->_getTextSize().width + 2*buttonPadding;
- buttonSize.height = (*button)->_getTextSize().height + 2*buttonPadding;
-
+
+ buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding;
+ buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding;
+
(*button)->setCoord(buttonCord);
(*button)->setSize(buttonSize);
-
+
left += buttonSize.width + buttonLeftPadding;
}
}
else
{
// among each other
-
+
if(biggestButtonWidth > textSize.width) {
mainWidgetSize.width = biggestButtonWidth + buttonTopPadding;
}
@@ -321,46 +320,46 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan
mainWidgetSize.width = textSize.width + 3*textPadding;
}
mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding;
-
+
std::cout << "biggestButtonWidth " << biggestButtonWidth << " textSize.width " << textSize.width << std::endl;
std::cout << "width " << mainWidgetSize.width << " height " << mainWidgetSize.height << std::endl;
mMainWidget->setSize(mainWidgetSize);
-
+
MyGUI::IntCoord absCoord;
absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2;
absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2;
-
+
mMainWidget->setCoord(absCoord);
mMainWidget->setSize(mainWidgetSize);
-
-
+
+
MyGUI::IntCoord messageWidgetCoord;
messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2;
messageWidgetCoord.top = textPadding;
mMessageWidget->setCoord(messageWidgetCoord);
-
+
mMessageWidget->setSize(textSize);
-
+
MyGUI::IntCoord buttonCord;
MyGUI::IntSize buttonSize(0, buttonHeight);
-
+
int top = textButtonPadding + buttonTopPadding + textSize.height;
-
+
std::vector::const_iterator button;
for(button = mButtons.begin(); button != mButtons.end(); ++button)
{
- buttonSize.width = (*button)->_getTextSize().width + buttonPadding*2;
- buttonSize.height = (*button)->_getTextSize().height + buttonPadding*2;
-
+ buttonSize.width = (*button)->getTextSize().width + buttonPadding*2;
+ buttonSize.height = (*button)->getTextSize().height + buttonPadding*2;
+
buttonCord.top = top;
buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/
-
+
(*button)->setCoord(buttonCord);
(*button)->setSize(buttonSize);
-
+
top += buttonSize.height + 2*buttonTopPadding;
}
-
+
}
}
@@ -387,8 +386,3 @@ int InteractiveMessageBox::readPressedButton ()
mButtonPressed = -1;
return pressed;
}
-
-
-
-
-
diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp
index bf3307accf..33155b2a00 100644
--- a/apps/openmw/mwgui/messagebox.hpp
+++ b/apps/openmw/mwgui/messagebox.hpp
@@ -7,6 +7,7 @@
#include "window_base.hpp"
#include "window_manager.hpp"
+#undef MessageBox
namespace MWGui
{
diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp
index 037f97fc36..880c0bc520 100644
--- a/apps/openmw/mwgui/race.cpp
+++ b/apps/openmw/mwgui/race.cpp
@@ -34,7 +34,7 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager)
headRotate->setScrollRange(50);
headRotate->setScrollPosition(20);
headRotate->setScrollViewPage(10);
- headRotate->eventScrollChangePosition = MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
+ headRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
// Set up next/previous buttons
MyGUI::ButtonPtr prevButton, nextButton;
@@ -42,27 +42,27 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager)
setText("GenderChoiceT", mWindowManager.getGameSettingString("sRaceMenu2", "Change Sex"));
getWidget(prevButton, "PrevGenderButton");
getWidget(nextButton, "NextGenderButton");
- prevButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender);
- nextButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender);
+ prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender);
+ nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender);
setText("FaceChoiceT", mWindowManager.getGameSettingString("sRaceMenu3", "Change Face"));
getWidget(prevButton, "PrevFaceButton");
getWidget(nextButton, "NextFaceButton");
- prevButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace);
- nextButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace);
+ prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace);
+ nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace);
setText("HairChoiceT", mWindowManager.getGameSettingString("sRaceMenu3", "Change Hair"));
getWidget(prevButton, "PrevHairButton");
getWidget(nextButton, "NextHairButton");
- prevButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair);
- nextButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair);
+ prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair);
+ nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair);
setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu4", "Race"));
getWidget(raceList, "RaceList");
raceList->setScrollVisible(true);
- raceList->eventListSelectAccept = MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
- raceList->eventListMouseItemActivate = MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
- raceList->eventListChangePosition = MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
+ raceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
+ raceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
+ raceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
setText("SkillsT", mWindowManager.getGameSettingString("sBonusSkillTitle", "Skill Bonus"));
getWidget(skillList, "SkillList");
@@ -72,11 +72,11 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager)
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
- backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onBackClicked);
+ backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
- okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onOkClicked);
+ okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked);
updateRaces();
updateSkills();
@@ -157,7 +157,7 @@ void RaceDialog::onBackClicked(MyGUI::Widget* _sender)
eventBack();
}
-void RaceDialog::onHeadRotate(MyGUI::VScroll*, size_t _position)
+void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position)
{
// TODO: Rotate head
}
@@ -192,7 +192,7 @@ void RaceDialog::onSelectNextHair(MyGUI::Widget*)
hairIndex = wrap(hairIndex - 1, hairCount);
}
-void RaceDialog::onSelectRace(MyGUI::List* _sender, size_t _index)
+void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp
index f2aac3a18c..bcd3b5185f 100644
--- a/apps/openmw/mwgui/race.hpp
+++ b/apps/openmw/mwgui/race.hpp
@@ -46,7 +46,7 @@ namespace MWGui
void open();
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
/** Event : Back button clicked.\n
signature : void method()\n
@@ -54,7 +54,7 @@ namespace MWGui
EventHandle_Void eventBack;
protected:
- void onHeadRotate(MyGUI::VScroll* _sender, size_t _position);
+ void onHeadRotate(MyGUI::ScrollBar* _sender, size_t _position);
void onSelectPreviousGender(MyGUI::Widget* _sender);
void onSelectNextGender(MyGUI::Widget* _sender);
@@ -65,7 +65,7 @@ namespace MWGui
void onSelectPreviousHair(MyGUI::Widget* _sender);
void onSelectNextHair(MyGUI::Widget* _sender);
- void onSelectRace(MyGUI::List* _sender, size_t _index);
+ void onSelectRace(MyGUI::ListBox* _sender, size_t _index);
void onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender);
@@ -76,8 +76,8 @@ namespace MWGui
void updateSpellPowers();
MyGUI::CanvasPtr appearanceBox;
- MyGUI::ListPtr raceList;
- MyGUI::HScrollPtr headRotate;
+ MyGUI::ListBox* raceList;
+ MyGUI::ScrollBar* headRotate;
MyGUI::WidgetPtr skillList;
std::vector skillItems;
diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp
index e770ec2351..cb0d9969c6 100644
--- a/apps/openmw/mwgui/review.cpp
+++ b/apps/openmw/mwgui/review.cpp
@@ -28,22 +28,22 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager)
getWidget(nameWidget, "NameText");
getWidget(button, "NameButton");
button->setCaption(mWindowManager.getGameSettingString("sName", ""));
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);;
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);;
getWidget(raceWidget, "RaceText");
getWidget(button, "RaceButton");
button->setCaption(mWindowManager.getGameSettingString("sRace", ""));
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);;
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);;
getWidget(classWidget, "ClassText");
getWidget(button, "ClassButton");
button->setCaption(mWindowManager.getGameSettingString("sClass", ""));
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);;
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);;
getWidget(birthSignWidget, "SignText");
getWidget(button, "SignButton");
button->setCaption(mWindowManager.getGameSettingString("sBirthSign", ""));
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);;
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);;
// Setup dynamic stats
getWidget(health, "Health");
@@ -75,25 +75,25 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager)
getWidget(skillClientWidget, "SkillClient");
getWidget(skillScrollerWidget, "SkillScroller");
- skillScrollerWidget->eventScrollChangePosition = MyGUI::newDelegate(this, &ReviewDialog::onScrollChangePosition);
+ skillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &ReviewDialog::onScrollChangePosition);
updateScroller();
for (int i = 0; i < ESM::Skill::Length; ++i)
{
skillValues.insert(std::make_pair(i, MWMechanics::Stat()));
- skillWidgetMap.insert(std::make_pair(i, static_cast (0)));
+ skillWidgetMap.insert(std::make_pair(i, static_cast (0)));
}
- static_cast(mMainWidget)->eventWindowChangeCoord = MyGUI::newDelegate(this, &ReviewDialog::onWindowResize);
+ static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ReviewDialog::onWindowResize);
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
- backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &ReviewDialog::onBackClicked);
+ backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
- okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &ReviewDialog::onOkClicked);
+ okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked);
}
void ReviewDialog::open()
@@ -102,7 +102,7 @@ void ReviewDialog::open()
setVisible(true);
}
-void ReviewDialog::onScrollChangePosition(MyGUI::VScrollPtr scroller, size_t pos)
+void ReviewDialog::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos)
{
int diff = lastPos - pos;
// Adjust position of all widget according to difference
@@ -176,7 +176,7 @@ void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const M
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value)
{
skillValues[skillId] = value;
- MyGUI::StaticTextPtr widget = skillWidgetMap[skillId];
+ MyGUI::TextBox* widget = skillWidgetMap[skillId];
if (widget)
{
float modified = value.getModified(), base = value.getBase();
@@ -210,7 +210,7 @@ void ReviewDialog::configureSkills(const std::vector& major, const std::vec
}
}
-void ReviewDialog::setStyledText(MyGUI::StaticTextPtr widget, ColorStyle style, const std::string &value)
+void ReviewDialog::setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value)
{
widget->setCaption(value);
if (style == CS_Super)
@@ -223,7 +223,7 @@ void ReviewDialog::setStyledText(MyGUI::StaticTextPtr widget, ColorStyle style,
void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
- MyGUI::StaticImagePtr separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default);
+ MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default);
skillWidgets.push_back(separator);
coord1.top += separator->getHeight();
@@ -232,7 +232,7 @@ void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2
void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
- MyGUI::StaticTextPtr groupWidget = skillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default);
+ MyGUI::TextBox* groupWidget = skillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default);
groupWidget->setCaption(label);
skillWidgets.push_back(groupWidget);
@@ -240,14 +240,15 @@ void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, M
coord2.top += lineHeight;
}
-MyGUI::StaticTextPtr ReviewDialog::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
+MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
- MyGUI::StaticTextPtr skillNameWidget, skillValueWidget;
+ MyGUI::TextBox* skillNameWidget;
+ MyGUI::TextBox* skillValueWidget;
- skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default);
+ skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default);
skillNameWidget->setCaption(text);
- skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default);
+ skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default);
setStyledText(skillValueWidget, style, value);
skillWidgets.push_back(skillNameWidget);
@@ -261,9 +262,9 @@ MyGUI::StaticTextPtr ReviewDialog::addValueItem(const std::string text, const st
void ReviewDialog::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
- MyGUI::StaticTextPtr skillNameWidget;
+ MyGUI::TextBox* skillNameWidget;
- skillNameWidget = skillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
+ skillNameWidget = skillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
skillNameWidget->setCaption(text);
skillWidgets.push_back(skillNameWidget);
@@ -299,7 +300,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId
style = CS_Super;
else if (modified < base)
style = CS_Sub;
- MyGUI::StaticTextPtr widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), style, coord1, coord2);
+ MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), style, coord1, coord2);
skillWidgetMap[skillId] = widget;
}
}
diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp
index 5846804f7f..588c1b6b5d 100644
--- a/apps/openmw/mwgui/review.hpp
+++ b/apps/openmw/mwgui/review.hpp
@@ -49,8 +49,8 @@ namespace MWGui
void open();
// Events
- typedef delegates::CDelegate0 EventHandle_Void;
- typedef delegates::CDelegate1 EventHandle_Int;
+ typedef delegates::CMultiDelegate0 EventHandle_Void;
+ typedef delegates::CMultiDelegate1 EventHandle_Int;
/** Event : Back button clicked.\n
signature : void method()\n
@@ -75,23 +75,23 @@ namespace MWGui
CS_Normal,
CS_Super
};
- void setStyledText(MyGUI::StaticTextPtr widget, ColorStyle style, const std::string &value);
+ void setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value);
void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
- MyGUI::StaticTextPtr addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
+ MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void updateScroller();
void updateSkillArea();
- void onScrollChangePosition(MyGUI::VScrollPtr scroller, size_t pos);
+ void onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos);
void onWindowResize(MyGUI::Window* window);
static const int lineHeight;
- MyGUI::StaticTextPtr nameWidget, raceWidget, classWidget, birthSignWidget;
+ MyGUI::TextBox *nameWidget, *raceWidget, *classWidget, *birthSignWidget;
MyGUI::WidgetPtr skillAreaWidget, skillClientWidget;
- MyGUI::VScrollPtr skillScrollerWidget;
+ MyGUI::ScrollBar* skillScrollerWidget;
int lastPos, clientHeight;
Widgets::MWDynamicStatPtr health, magicka, fatigue;
@@ -100,7 +100,7 @@ namespace MWGui
SkillList majorSkills, minorSkills, miscSkills;
std::map > skillValues;
- std::map skillWidgetMap;
+ std::map skillWidgetMap;
std::string name, raceId, birthSignId;
ESM::Class klass;
std::vector skillWidgets; //< Skills and other information
diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp
index 30a4015e33..12b0dcc793 100644
--- a/apps/openmw/mwgui/stats_window.cpp
+++ b/apps/openmw/mwgui/stats_window.cpp
@@ -13,9 +13,22 @@ const int StatsWindow::lineHeight = 18;
StatsWindow::StatsWindow (WindowManager& parWindowManager)
: WindowBase("openmw_stats_window_layout.xml", parWindowManager)
+ , skillAreaWidget(NULL)
+ , skillClientWidget(NULL)
+ , skillScrollerWidget(NULL)
, lastPos(0)
+ , clientHeight(0)
+ , majorSkills()
+ , minorSkills()
+ , miscSkills()
+ , skillValues()
+ , skillWidgetMap()
+ , factionWidgetMap()
+ , factions()
+ , birthSignId()
, reputation(0)
, bounty(0)
+ , skillWidgets()
{
setCoord(0,0,498, 342);
@@ -48,20 +61,20 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager)
getWidget(skillClientWidget, "SkillClient");
getWidget(skillScrollerWidget, "SkillScroller");
- skillScrollerWidget->eventScrollChangePosition = MyGUI::newDelegate(this, &StatsWindow::onScrollChangePosition);
+ skillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &StatsWindow::onScrollChangePosition);
updateScroller();
for (int i = 0; i < ESM::Skill::Length; ++i)
{
skillValues.insert(std::pair >(i, MWMechanics::Stat()));
- skillWidgetMap.insert(std::pair(i, nullptr));
+ skillWidgetMap.insert(std::pair(i, nullptr));
}
MyGUI::WindowPtr t = static_cast(mMainWidget);
- t->eventWindowChangeCoord = MyGUI::newDelegate(this, &StatsWindow::onWindowResize);
+ t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize);
}
-void StatsWindow::onScrollChangePosition(MyGUI::VScrollPtr scroller, size_t pos)
+void StatsWindow::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos)
{
int diff = lastPos - pos;
// Adjust position of all widget according to difference
@@ -95,10 +108,10 @@ void StatsWindow::setBar(const std::string& name, const std::string& tname, int
void StatsWindow::setPlayerName(const std::string& playerName)
{
- mMainWidget->setCaption(playerName);
+ static_cast(mMainWidget)->setCaption(playerName);
}
-void StatsWindow::setStyledText(MyGUI::StaticTextPtr widget, ColorStyle style, const std::string &value)
+void StatsWindow::setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value)
{
widget->setCaption(value);
if (style == CS_Super)
@@ -175,7 +188,7 @@ void StatsWindow::setValue (const std::string& id, int value)
void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value)
{
skillValues[parSkill] = value;
- MyGUI::StaticTextPtr widget = skillWidgetMap[(int)parSkill];
+ MyGUI::TextBox* widget = skillWidgetMap[(int)parSkill];
if (widget)
{
float modified = value.getModified(), base = value.getBase();
@@ -221,7 +234,7 @@ void StatsWindow::setBirthSign (const std::string& signId)
void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
- MyGUI::StaticImagePtr separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default);
+ MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default);
skillWidgets.push_back(separator);
coord1.top += separator->getHeight();
@@ -230,7 +243,7 @@ void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
- MyGUI::StaticTextPtr groupWidget = skillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default);
+ MyGUI::TextBox* groupWidget = skillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default);
groupWidget->setCaption(label);
skillWidgets.push_back(groupWidget);
@@ -238,14 +251,14 @@ void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, My
coord2.top += lineHeight;
}
-MyGUI::StaticTextPtr StatsWindow::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
+MyGUI::TextBox* StatsWindow::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
- MyGUI::StaticTextPtr skillNameWidget, skillValueWidget;
+ MyGUI::TextBox *skillNameWidget, *skillValueWidget;
- skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default);
+ skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default);
skillNameWidget->setCaption(text);
- skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default);
+ skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default);
setStyledText(skillValueWidget, style, value);
skillWidgets.push_back(skillNameWidget);
@@ -259,9 +272,9 @@ MyGUI::StaticTextPtr StatsWindow::addValueItem(const std::string text, const std
void StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
- MyGUI::StaticTextPtr skillNameWidget;
+ MyGUI::TextBox* skillNameWidget;
- skillNameWidget = skillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
+ skillNameWidget = skillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
skillNameWidget->setCaption(text);
skillWidgets.push_back(skillNameWidget);
@@ -297,7 +310,7 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId,
style = CS_Super;
else if (modified < base)
style = CS_Sub;
- MyGUI::StaticTextPtr widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), style, coord1, coord2);
+ MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), style, coord1, coord2);
skillWidgetMap[skillId] = widget;
}
}
diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp
index 9db5c240b1..2ff170f571 100644
--- a/apps/openmw/mwgui/stats_window.hpp
+++ b/apps/openmw/mwgui/stats_window.hpp
@@ -49,26 +49,26 @@ namespace MWGui
CS_Normal,
CS_Super
};
- void setStyledText(MyGUI::StaticTextPtr widget, ColorStyle style, const std::string &value);
+ void setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value);
void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
- MyGUI::StaticTextPtr addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
+ MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void updateScroller();
- void onScrollChangePosition(MyGUI::VScrollPtr scroller, size_t pos);
+ void onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos);
void onWindowResize(MyGUI::Window* window);
static const int lineHeight;
MyGUI::WidgetPtr skillAreaWidget, skillClientWidget;
- MyGUI::VScrollPtr skillScrollerWidget;
+ MyGUI::ScrollBar* skillScrollerWidget;
int lastPos, clientHeight;
SkillList majorSkills, minorSkills, miscSkills;
std::map > skillValues;
- std::map skillWidgetMap;
+ std::map skillWidgetMap;
std::map factionWidgetMap;
FactionList factions; ///< Stores a list of factions and the current rank
std::string birthSignId;
diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp
index 83ebef6576..8ac07e7668 100644
--- a/apps/openmw/mwgui/text_input.cpp
+++ b/apps/openmw/mwgui/text_input.cpp
@@ -10,12 +10,12 @@ TextInputDialog::TextInputDialog(WindowManager& parWindowManager)
center();
getWidget(textEdit, "TextEdit");
- textEdit->eventEditSelectAccept = newDelegate(this, &TextInputDialog::onTextAccepted);
+ textEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted);
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
- okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &TextInputDialog::onOkClicked);
+ okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked);
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit);
diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp
index f62da2bab9..74603aaf1c 100644
--- a/apps/openmw/mwgui/widgets.cpp
+++ b/apps/openmw/mwgui/widgets.cpp
@@ -62,24 +62,24 @@ void MWSkill::updateWidgets()
{
if (skillId == ESM::Skill::Length)
{
- skillNameWidget->setCaption("");
+ static_cast(skillNameWidget)->setCaption("");
}
else
{
const std::string &name = manager->getGameSettingString(ESM::Skill::sSkillNameIds[skillId], "");
- skillNameWidget->setCaption(name);
+ static_cast(skillNameWidget)->setCaption(name);
}
}
if (skillValueWidget)
{
SkillValue::Type modified = value.getModified(), base = value.getBase();
- skillValueWidget->setCaption(boost::lexical_cast(modified));
+ static_cast(skillValueWidget)->setCaption(boost::lexical_cast(modified));
if (modified > base)
- skillValueWidget->setState("increased");
+ skillValueWidget->_setWidgetState("increased");
else if (modified < base)
- skillValueWidget->setState("decreased");
+ skillValueWidget->_setWidgetState("decreased");
else
- skillValueWidget->setState("normal");
+ skillValueWidget->_setWidgetState("normal");
}
}
@@ -88,59 +88,32 @@ void MWSkill::onClicked(MyGUI::Widget* _sender)
eventClicked(this);
}
-void MWSkill::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
-{
- Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
-
- initialiseWidgetSkin(_info);
-}
-
MWSkill::~MWSkill()
{
- shutdownWidgetSkin();
}
-void MWSkill::baseChangeWidgetSkin(ResourceSkin* _info)
+void MWSkill::initialiseOverride()
{
- shutdownWidgetSkin();
- Base::baseChangeWidgetSkin(_info);
- initialiseWidgetSkin(_info);
-}
+ Base::initialiseOverride();
-void MWSkill::initialiseWidgetSkin(ResourceSkin* _info)
-{
- for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
+ assignWidget(skillNameWidget, "StatName");
+ assignWidget(skillValueWidget, "StatValue");
+
+ MyGUI::ButtonPtr button;
+ assignWidget(button, "StatNameButton");
+ if (button)
{
- const std::string &name = *(*iter)->_getInternalData();
- if (name == "StatName")
- {
- MYGUI_DEBUG_ASSERT( ! skillNameWidget, "widget already assigned");
- skillNameWidget = (*iter)->castType();
- }
- else if (name == "StatValue")
- {
- MYGUI_DEBUG_ASSERT( ! skillValueWidget, "widget already assigned");
- skillValueWidget = (*iter)->castType();
- }
- else if (name == "StatNameButton")
- {
- MYGUI_DEBUG_ASSERT( ! skillNameWidget, "widget already assigned");
- MyGUI::ButtonPtr button = (*iter)->castType();
- skillNameWidget = button;
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &MWSkill::onClicked);
- }
- else if (name == "StatValueButton")
- {
- MYGUI_DEBUG_ASSERT( ! skillValueWidget, "widget already assigned");
- MyGUI::ButtonPtr button = (*iter)->castType();
- skillNameWidget = button;
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &MWSkill::onClicked);
- }
+ skillNameWidget = button;
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked);
}
-}
-void MWSkill::shutdownWidgetSkin()
-{
+ button = 0;
+ assignWidget(button, "StatValueButton");
+ if (button)
+ {
+ skillNameWidget = button;
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked);
+ }
}
/* MWAttribute */
@@ -176,7 +149,7 @@ void MWAttribute::updateWidgets()
{
if (id < 0 || id >= 8)
{
- attributeNameWidget->setCaption("");
+ static_cast(attributeNameWidget)->setCaption("");
}
else
{
@@ -191,75 +164,48 @@ void MWAttribute::updateWidgets()
"sAttributeLuck"
};
const std::string &name = manager->getGameSettingString(attributes[id], "");
- attributeNameWidget->setCaption(name);
+ static_cast(attributeNameWidget)->setCaption(name);
}
}
if (attributeValueWidget)
{
AttributeValue::Type modified = value.getModified(), base = value.getBase();
- attributeValueWidget->setCaption(boost::lexical_cast(modified));
+ static_cast(attributeValueWidget)->setCaption(boost::lexical_cast(modified));
if (modified > base)
- attributeValueWidget->setState("increased");
+ attributeValueWidget->_setWidgetState("increased");
else if (modified < base)
- attributeValueWidget->setState("decreased");
+ attributeValueWidget->_setWidgetState("decreased");
else
- attributeValueWidget->setState("normal");
+ attributeValueWidget->_setWidgetState("normal");
}
}
-void MWAttribute::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
-{
- Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
-
- initialiseWidgetSkin(_info);
-}
-
MWAttribute::~MWAttribute()
{
- shutdownWidgetSkin();
}
-void MWAttribute::baseChangeWidgetSkin(ResourceSkin* _info)
+void MWAttribute::initialiseOverride()
{
- shutdownWidgetSkin();
- Base::baseChangeWidgetSkin(_info);
- initialiseWidgetSkin(_info);
-}
+ Base::initialiseOverride();
-void MWAttribute::initialiseWidgetSkin(ResourceSkin* _info)
-{
- for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
+ assignWidget(attributeNameWidget, "StatName");
+ assignWidget(attributeValueWidget, "StatValue");
+
+ MyGUI::ButtonPtr button;
+ assignWidget(button, "StatNameButton");
+ if (button)
{
- const std::string &name = *(*iter)->_getInternalData();
- if (name == "StatName")
- {
- MYGUI_DEBUG_ASSERT( ! attributeNameWidget, "widget already assigned");
- attributeNameWidget = (*iter)->castType();
- }
- else if (name == "StatValue")
- {
- MYGUI_DEBUG_ASSERT( ! attributeValueWidget, "widget already assigned");
- attributeValueWidget = (*iter)->castType();
- }
- else if (name == "StatNameButton")
- {
- MYGUI_DEBUG_ASSERT( ! attributeNameWidget, "widget already assigned");
- MyGUI::ButtonPtr button = (*iter)->castType();
- attributeNameWidget = button;
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &MWAttribute::onClicked);
- }
- else if (name == "StatValue")
- {
- MYGUI_DEBUG_ASSERT( ! attributeValueWidget, "widget already assigned");
- MyGUI::ButtonPtr button = (*iter)->castType();
- attributeNameWidget = button;
- button->eventMouseButtonClick = MyGUI::newDelegate(this, &MWAttribute::onClicked);
- }
+ attributeNameWidget = button;
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked);
}
-}
-void MWAttribute::shutdownWidgetSkin()
-{
+ button = 0;
+ assignWidget(button, "StatValueButton");
+ if (button)
+ {
+ attributeValueWidget = button;
+ button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked);
+ }
}
/* MWSpell */
@@ -301,45 +247,20 @@ void MWSpell::updateWidgets()
const ESMS::ESMStore &store = mWindowManager->getStore();
const ESM::Spell *spell = store.spells.search(id);
if (spell)
- spellNameWidget->setCaption(spell->name);
+ static_cast(spellNameWidget)->setCaption(spell->name);
else
- spellNameWidget->setCaption("");
+ static_cast(spellNameWidget)->setCaption("");
}
}
-void MWSpell::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
+void MWSpell::initialiseOverride()
{
- Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
+ Base::initialiseOverride();
- initialiseWidgetSkin(_info);
+ assignWidget(spellNameWidget, "StatName");
}
MWSpell::~MWSpell()
-{
- shutdownWidgetSkin();
-}
-
-void MWSpell::baseChangeWidgetSkin(ResourceSkin* _info)
-{
- shutdownWidgetSkin();
- Base::baseChangeWidgetSkin(_info);
- initialiseWidgetSkin(_info);
-}
-
-void MWSpell::initialiseWidgetSkin(ResourceSkin* _info)
-{
- for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
- {
- const std::string &name = *(*iter)->_getInternalData();
- if (name == "StatName")
- {
- MYGUI_DEBUG_ASSERT( ! spellNameWidget, "widget already assigned");
- spellNameWidget = (*iter)->castType();
- }
- }
-}
-
-void MWSpell::shutdownWidgetSkin()
{
}
@@ -408,10 +329,10 @@ void MWSpellEffect::updateWidgets()
spellLine += " on Touch";
else if (effect.range == ESM::RT_Target)
spellLine += " on Target";
- textWidget->setCaption(spellLine);
+ static_cast(textWidget)->setCaption(spellLine);
}
else
- textWidget->setCaption("");
+ static_cast(textWidget)->setCaption("");
}
if (imageWidget)
{
@@ -421,45 +342,16 @@ void MWSpellEffect::updateWidgets()
}
}
-void MWSpellEffect::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
-{
- Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
-
- initialiseWidgetSkin(_info);
-}
-
MWSpellEffect::~MWSpellEffect()
{
- shutdownWidgetSkin();
}
-void MWSpellEffect::baseChangeWidgetSkin(ResourceSkin* _info)
+void MWSpellEffect::initialiseOverride()
{
- shutdownWidgetSkin();
- Base::baseChangeWidgetSkin(_info);
- initialiseWidgetSkin(_info);
-}
+ Base::initialiseOverride();
-void MWSpellEffect::initialiseWidgetSkin(ResourceSkin* _info)
-{
- for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
- {
- const std::string &name = *(*iter)->_getInternalData();
- if (name == "Text")
- {
- MYGUI_DEBUG_ASSERT( ! textWidget, "widget already assigned");
- textWidget = (*iter)->castType();
- }
- else if (name == "Image")
- {
- MYGUI_DEBUG_ASSERT( ! imageWidget, "widget already assigned");
- imageWidget = (*iter)->castType();
- }
- }
-}
-
-void MWSpellEffect::shutdownWidgetSkin()
-{
+ assignWidget(textWidget, "Text");
+ assignWidget(imageWidget, "Image");
}
/* MWDynamicStat */
@@ -491,60 +383,27 @@ void MWDynamicStat::setValue(int cur, int max_)
{
std::stringstream out;
out << value << "/" << max;
- barTextWidget->setCaption(out.str().c_str());
+ static_cast(barTextWidget)->setCaption(out.str().c_str());
}
else
- barTextWidget->setCaption("");
+ static_cast(barTextWidget)->setCaption("");
}
}
void MWDynamicStat::setTitle(const std::string text)
{
if (textWidget)
- textWidget->setCaption(text);
-}
-
-void MWDynamicStat::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
-{
- Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
-
- initialiseWidgetSkin(_info);
+ static_cast(textWidget)->setCaption(text);
}
MWDynamicStat::~MWDynamicStat()
{
- shutdownWidgetSkin();
}
-void MWDynamicStat::baseChangeWidgetSkin(ResourceSkin* _info)
+void MWDynamicStat::initialiseOverride()
{
- shutdownWidgetSkin();
- Base::baseChangeWidgetSkin(_info);
- initialiseWidgetSkin(_info);
-}
+ Base::initialiseOverride();
-void MWDynamicStat::initialiseWidgetSkin(ResourceSkin* _info)
-{
- for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
- {
- const std::string &name = *(*iter)->_getInternalData();
- if (name == "Text")
- {
- MYGUI_DEBUG_ASSERT( ! textWidget, "widget already assigned");
- textWidget = (*iter)->castType();
- }
- else if (name == "Bar")
- {
- MYGUI_DEBUG_ASSERT( ! barWidget, "widget already assigned");
- barWidget = (*iter)->castType();
- }
- else if (name == "BarText")
- {
- MYGUI_DEBUG_ASSERT( ! barTextWidget, "widget already assigned");
- barTextWidget = (*iter)->castType();
- }
- }
-}
-
-void MWDynamicStat::shutdownWidgetSkin()
-{
+ assignWidget(textWidget, "Text");
+ assignWidget(barWidget, "Bar");
+ assignWidget(barTextWidget, "BarText");
}
diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp
index cba8fefd32..a7916285eb 100644
--- a/apps/openmw/mwgui/widgets.hpp
+++ b/apps/openmw/mwgui/widgets.hpp
@@ -7,6 +7,9 @@
#include "../mwmechanics/stat.hpp"
+#undef MYGUI_EXPORT
+#define MYGUI_EXPORT
+
/*
This file contains various custom widgets used in OpenMW.
*/
@@ -38,26 +41,21 @@ namespace MWGui
const SkillValue& getSkillValue() const { return value; }
// Events
- typedef delegates::CDelegate1 EventHandle_SkillVoid;
+ typedef delegates::CMultiDelegate1 EventHandle_SkillVoid;
/** Event : Skill clicked.\n
signature : void method(MWSkill* _sender)\n
*/
EventHandle_SkillVoid eventClicked;
- /*internal:*/
- virtual void _initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name);
-
protected:
virtual ~MWSkill();
- void baseChangeWidgetSkin(ResourceSkin* _info);
+ virtual void initialiseOverride();
void onClicked(MyGUI::Widget* _sender);
private:
- void initialiseWidgetSkin(ResourceSkin* _info);
- void shutdownWidgetSkin();
void updateWidgets();
@@ -85,26 +83,21 @@ namespace MWGui
const AttributeValue& getAttributeValue() const { return value; }
// Events
- typedef delegates::CDelegate1 EventHandle_AttributeVoid;
+ typedef delegates::CMultiDelegate1 EventHandle_AttributeVoid;
/** Event : Attribute clicked.\n
signature : void method(MWAttribute* _sender)\n
*/
EventHandle_AttributeVoid eventClicked;
- /*internal:*/
- virtual void _initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name);
-
protected:
virtual ~MWAttribute();
- void baseChangeWidgetSkin(ResourceSkin* _info);
+ virtual void initialiseOverride();
void onClicked(MyGUI::Widget* _sender);
private:
- void initialiseWidgetSkin(ResourceSkin* _info);
- void shutdownWidgetSkin();
void updateWidgets();
@@ -130,23 +123,17 @@ namespace MWGui
const std::string &getSpellId() const { return id; }
- /*internal:*/
- virtual void _initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name);
-
protected:
virtual ~MWSpell();
- void baseChangeWidgetSkin(ResourceSkin* _info);
+ virtual void initialiseOverride();
private:
- void initialiseWidgetSkin(ResourceSkin* _info);
- void shutdownWidgetSkin();
-
void updateWidgets();
WindowManager* mWindowManager;
std::string id;
- MyGUI::StaticTextPtr spellNameWidget;
+ MyGUI::TextBox* spellNameWidget;
};
typedef MWSpell* MWSpellPtr;
@@ -163,24 +150,19 @@ namespace MWGui
const SpellEffectValue &getSpellEffect() const { return effect; }
- /*internal:*/
- virtual void _initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name);
-
protected:
virtual ~MWSpellEffect();
- void baseChangeWidgetSkin(ResourceSkin* _info);
-
+ virtual void initialiseOverride();
+
private:
- void initialiseWidgetSkin(ResourceSkin* _info);
- void shutdownWidgetSkin();
void updateWidgets();
WindowManager* mWindowManager;
SpellEffectValue effect;
- MyGUI::StaticImagePtr imageWidget;
- MyGUI::StaticTextPtr textWidget;
+ MyGUI::ImageBox* imageWidget;
+ MyGUI::TextBox* textWidget;
};
typedef MWSpellEffect* MWSpellEffectPtr;
@@ -196,22 +178,17 @@ namespace MWGui
int getValue() const { return value; }
int getMax() const { return max; }
- /*internal:*/
- virtual void _initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name);
-
protected:
virtual ~MWDynamicStat();
- void baseChangeWidgetSkin(ResourceSkin* _info);
+ virtual void initialiseOverride();
private:
- void initialiseWidgetSkin(ResourceSkin* _info);
- void shutdownWidgetSkin();
int value, max;
- MyGUI::StaticTextPtr textWidget;
+ MyGUI::TextBox* textWidget;
MyGUI::ProgressPtr barWidget;
- MyGUI::StaticTextPtr barTextWidget;
+ MyGUI::TextBox* barTextWidget;
};
typedef MWDynamicStat* MWDynamicStatPtr;
diff --git a/apps/openmw/mwgui/window_base.cpp b/apps/openmw/mwgui/window_base.cpp
index 192dcd988d..1eb126a74c 100644
--- a/apps/openmw/mwgui/window_base.cpp
+++ b/apps/openmw/mwgui/window_base.cpp
@@ -16,7 +16,7 @@ void WindowBase::open()
void WindowBase::center()
{
// Centre dialog
- MyGUI::IntSize gameWindowSize = mWindowManager.getGui()->getViewSize();
+ MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
MyGUI::IntCoord coord = mMainWidget->getCoord();
coord.left = (gameWindowSize.width - coord.width)/2;
coord.top = (gameWindowSize.height - coord.height)/2;
diff --git a/apps/openmw/mwgui/window_base.hpp b/apps/openmw/mwgui/window_base.hpp
index 84fb601e32..99ddbe9181 100644
--- a/apps/openmw/mwgui/window_base.hpp
+++ b/apps/openmw/mwgui/window_base.hpp
@@ -13,7 +13,7 @@ namespace MWGui
WindowBase(const std::string& parLayout, WindowManager& parWindowManager);
// Events
- typedef MyGUI::delegates::CDelegate1 EventHandle_WindowBase;
+ typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase;
virtual void open();
void center();
diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp
index baf8548143..a04e2dcb8b 100644
--- a/apps/openmw/mwgui/window_manager.cpp
+++ b/apps/openmw/mwgui/window_manager.cpp
@@ -22,27 +22,52 @@ using namespace MWGui;
WindowManager::WindowManager(MWWorld::Environment& environment,
const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath)
- : environment(environment)
+ : mGuiManager(NULL)
+ , environment(environment)
+ , hud(NULL)
+ , map(NULL)
+ , menu(NULL)
+ , stats(NULL)
+ , mMessageBoxManager(NULL)
+ , console(NULL)
+ , mJournal(NULL)
, dialogueWindow(nullptr)
+ , mCharGen(NULL)
+ , playerClass()
+ , playerName()
+ , playerRaceId()
+ , playerBirthSignId()
+ , playerAttributes()
+ , playerMajorSkills()
+ , playerMinorSkills()
+ , playerSkillValues()
+ , playerHealth()
+ , playerMagicka()
+ , playerFatigue()
+ , gui(NULL)
, mode(GM_Game)
, nextMode(GM_Game)
, needModeChange(false)
+ , garbageDialogs()
, shown(GW_ALL)
, allowed(newGame ? GW_None : GW_ALL)
+ , showFPSLevel(fpsLevel)
+ , mFPS(0.0f)
+ , mTriangleCount(0)
+ , mBatchCount(0)
{
- showFPSLevel = fpsLevel;
// Set up the GUI system
mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath);
gui = mGuiManager->getGui();
//Register own widgets with MyGUI
- MyGUI::FactoryManager::getInstance().registerFactory("Widget");
+ MyGUI::FactoryManager::getInstance().registerFactory("Widget");
// Get size info from the Gui object
assert(gui);
- int w = gui->getViewSize().width;
- int h = gui->getViewSize().height;
+ int w = MyGUI::RenderManager::getInstance().getViewSize().width;
+ int h = MyGUI::RenderManager::getInstance().getViewSize().height;
hud = new HUD(w,h, showFPSLevel);
menu = new MainMenu(w,h);
@@ -153,7 +178,7 @@ void WindowManager::updateVisible()
dialogueWindow->setVisible(false);
// Mouse is visible whenever we're not in game mode
- gui->setVisiblePointer(isGuiMode());
+ MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
// If in game mode, don't show anything.
if(mode == GM_Game) //Use a switch/case structure
@@ -400,3 +425,47 @@ const ESMS::ESMStore& WindowManager::getStore() const
{
return environment.mWorld->getStore();
}
+
+void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell)
+{
+ if (!(cell->cell->data.flags & ESM::Cell::Interior))
+ {
+ std::string name;
+ if (cell->cell->name != "")
+ name = cell->cell->name;
+ else
+ name = cell->cell->region;
+
+ map->setCellName( name );
+
+ map->setCellPrefix("Cell");
+ hud->setCellPrefix("Cell");
+ map->setActiveCell( cell->cell->data.gridX, cell->cell->data.gridY );
+ hud->setActiveCell( cell->cell->data.gridX, cell->cell->data.gridY );
+ }
+ else
+ {
+ map->setCellName( cell->cell->name );
+ map->setCellPrefix( cell->cell->name );
+ hud->setCellPrefix( cell->cell->name );
+ }
+
+}
+
+void WindowManager::setInteriorMapTexture(const int x, const int y)
+{
+ map->setActiveCell(x,y, true);
+ hud->setActiveCell(x,y, true);
+}
+
+void WindowManager::setPlayerPos(const float x, const float y)
+{
+ map->setPlayerPos(x,y);
+ hud->setPlayerPos(x,y);
+}
+
+void WindowManager::setPlayerDir(const float x, const float y)
+{
+ map->setPlayerDir(x,y);
+ hud->setPlayerDir(x,y);
+}
diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp
index 0124c92392..582f438e8f 100644
--- a/apps/openmw/mwgui/window_manager.hpp
+++ b/apps/openmw/mwgui/window_manager.hpp
@@ -18,6 +18,7 @@
#include
#include
#include "../mwmechanics/stat.hpp"
+#include "../mwworld/ptr.hpp"
#include "mode.hpp"
namespace MyGUI
@@ -152,6 +153,12 @@ namespace MWGui
void setBounty (int bounty); ///< set the current bounty value
void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty
+ void changeCell(MWWorld::Ptr::CellStore* cell); ///< change the active cell
+ void setPlayerPos(const float x, const float y); ///< set player position in map space
+ void setPlayerDir(const float x, const float y); ///< set player view direction in map space
+
+ void setInteriorMapTexture(const int x, const int y);
+ ///< set the index of the map texture that should be used (for interiors)
template
void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr.
diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp
index d8ca78e3a5..6eb4a182bd 100644
--- a/apps/openmw/mwrender/actors.cpp
+++ b/apps/openmw/mwrender/actors.cpp
@@ -8,6 +8,15 @@ using namespace Ogre;
using namespace MWRender;
using namespace NifOgre;
+Actors::~Actors(){
+
+ std::map::iterator it = mAllActors.begin();
+ for (; it != mAllActors.end(); ++it) {
+ delete it->second;
+ it->second = NULL;
+ }
+}
+
void Actors::setMwRoot(Ogre::SceneNode* root){
mMwRoot = root;
}
@@ -61,6 +70,7 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr){
insertBegin(ptr, true, true);
CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mEnvironment, mRend);
//mAllActors.insert(std::pair(ptr,anim));
+ delete mAllActors[ptr];
mAllActors[ptr] = anim;
//mAllActors.push_back(&anim);*/
}
diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp
index 7179c08fb4..d49c6e0f8d 100644
--- a/apps/openmw/mwrender/actors.hpp
+++ b/apps/openmw/mwrender/actors.hpp
@@ -30,7 +30,7 @@ namespace MWRender{
public:
Actors(OEngine::Render::OgreRenderer& _rend, MWWorld::Environment& _env): mRend(_rend), mEnvironment(_env){}
- ~Actors(){}
+ ~Actors();
void setMwRoot(Ogre::SceneNode* root);
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
void insertCreature (const MWWorld::Ptr& ptr);
diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp
index 7b0d7015c0..f3a8f64d55 100644
--- a/apps/openmw/mwrender/animation.cpp
+++ b/apps/openmw/mwrender/animation.cpp
@@ -4,7 +4,30 @@
namespace MWRender{
std::map Animation::mUniqueIDs;
- Animation::~Animation(){
+ Animation::Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend)
+ : insert(NULL)
+ , mRend(_rend)
+ , mEnvironment(_env)
+ , vecRotPos()
+ , shapeparts()
+ , time(0.0f)
+ , startTime(0.0f)
+ , stopTime(0.0f)
+ , animate(0)
+ , rindexI()
+ , tindexI()
+ , shapeNumber(0)
+ , shapeIndexI()
+ , shapes(NULL)
+ , entityparts()
+ , transformations(NULL)
+ , textmappings(NULL)
+ , base(NULL)
+ {
+ }
+
+ Animation::~Animation()
+ {
}
std::string Animation::getUniqueID(std::string mesh){
diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp
index d1e8071f06..7692c71283 100644
--- a/apps/openmw/mwrender/animation.hpp
+++ b/apps/openmw/mwrender/animation.hpp
@@ -60,14 +60,14 @@ class Animation{
std::string getUniqueID(std::string mesh);
public:
- Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend): mRend(_rend), mEnvironment(_env), animate(0){};
- virtual void runAnimation(float timepassed) = 0;
- void startScript(std::string groupname, int mode, int loops);
- void stopScript();
-
-
- virtual ~Animation();
+ Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
+ virtual void runAnimation(float timepassed) = 0;
+ void startScript(std::string groupname, int mode, int loops);
+ void stopScript();
+
+
+ virtual ~Animation();
};
}
-#endif
\ No newline at end of file
+#endif
diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp
new file mode 100644
index 0000000000..ed218dc97d
--- /dev/null
+++ b/apps/openmw/mwrender/localmap.cpp
@@ -0,0 +1,305 @@
+#include "localmap.hpp"
+#include "renderingmanager.hpp"
+
+#include "../mwworld/environment.hpp"
+#include "../mwgui/window_manager.hpp"
+
+#include
+#include
+
+using namespace MWRender;
+using namespace Ogre;
+
+LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWWorld::Environment* env)
+{
+ mRendering = rend;
+ mEnvironment = env;
+
+ mCellCamera = mRendering->getScene()->createCamera("CellCamera");
+ mCellCamera->setProjectionType(PT_ORTHOGRAPHIC);
+ // look down -y
+ const float sqrt0pt5 = 0.707106781;
+ mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0));
+}
+
+LocalMap::~LocalMap()
+{
+ deleteBuffers();
+}
+
+void LocalMap::deleteBuffers()
+{
+ mBuffers.clear();
+}
+
+void LocalMap::saveTexture(const std::string& texname, const std::string& filename)
+{
+ TexturePtr tex = TextureManager::getSingleton().getByName(texname);
+ if (tex.isNull()) return;
+ HardwarePixelBufferSharedPtr readbuffer = tex->getBuffer();
+ readbuffer->lock(HardwareBuffer::HBL_NORMAL );
+ const PixelBox &readrefpb = readbuffer->getCurrentLock();
+ uchar *readrefdata = static_cast(readrefpb.data);
+
+ Image img;
+ img = img.loadDynamicImage (readrefdata, tex->getWidth(),
+ tex->getHeight(), tex->getFormat());
+ img.save("./" + filename);
+
+ readbuffer->unlock();
+}
+
+std::string LocalMap::coordStr(const int x, const int y)
+{
+ return StringConverter::toString(x) + "_" + StringConverter::toString(y);
+}
+
+void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell)
+{
+ if (!mInterior)
+ {
+ /*saveTexture("Cell_"+coordStr(mCellX, mCellY)+"_fog",
+ "Cell_"+coordStr(mCellX, mCellY)+"_fog.png");*/
+ }
+ else
+ {
+ Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
+ Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z);
+ /// \todo why is this workaround needed?
+ min *= 1.3;
+ max *= 1.3;
+ Vector2 length = max-min;
+
+ // divide into segments
+ const int segsX = std::ceil( length.x / sSize );
+ const int segsY = std::ceil( length.y / sSize );
+
+ for (int x=0; xcell->data.gridX, cell->cell->data.gridY);
+
+ int x = cell->cell->data.gridX;
+ int y = cell->cell->data.gridY;
+
+ render((x+0.5)*sSize, (-y-0.5)*sSize, -10000, 10000, sSize, sSize, name);
+}
+
+void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell,
+ AxisAlignedBox bounds)
+{
+ mInterior = true;
+ mBounds = bounds;
+
+ Vector2 z(bounds.getMaximum().y, bounds.getMinimum().y);
+ Vector2 min(bounds.getMinimum().x, bounds.getMinimum().z);
+ Vector2 max(bounds.getMaximum().x, bounds.getMaximum().z);
+
+ /// \todo why is this workaround needed?
+ min *= 1.3;
+ max *= 1.3;
+
+ Vector2 length = max-min;
+ Vector2 center(bounds.getCenter().x, bounds.getCenter().z);
+
+ // divide into segments
+ const int segsX = std::ceil( length.x / sSize );
+ const int segsY = std::ceil( length.y / sSize );
+
+ mInteriorName = cell->cell->name;
+
+ for (int x=0; xcell->name + "_" + coordStr(x,y));
+ }
+ }
+}
+
+void LocalMap::render(const float x, const float y,
+ const float zlow, const float zhigh,
+ const float xw, const float yw, const std::string& texture)
+{
+ // disable fog
+ // changing FOG_MODE is not a solution when using shaders, thus we have to push linear start/end
+ const float fStart = mRendering->getScene()->getFogStart();
+ const float fEnd = mRendering->getScene()->getFogEnd();
+ const ColourValue& clr = mRendering->getScene()->getFogColour();
+ mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, 1000000, 10000000);
+
+ // make everything visible
+ mRendering->getScene()->setAmbientLight(ColourValue(1,1,1));
+
+ mCellCamera->setPosition(Vector3(x, zhigh+100000, y));
+ //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 );
+ mCellCamera->setFarClipDistance(0); // infinite
+
+ mCellCamera->setOrthoWindow(xw, yw);
+
+ TexturePtr tex;
+ // try loading from memory
+ tex = TextureManager::getSingleton().getByName(texture);
+ if (tex.isNull())
+ {
+ // try loading from disk
+ //if (boost::filesystem::exists(texture+".jpg"))
+ //{
+ /// \todo
+ //}
+ //else
+ {
+ // render
+ tex = TextureManager::getSingleton().createManual(
+ texture,
+ ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
+ TEX_TYPE_2D,
+ xw*sMapResolution/sSize, yw*sMapResolution/sSize,
+ 0,
+ PF_R8G8B8,
+ TU_RENDERTARGET);
+
+ RenderTarget* rtt = tex->getBuffer()->getRenderTarget();
+ rtt->setAutoUpdated(false);
+ Viewport* vp = rtt->addViewport(mCellCamera);
+ vp->setOverlaysEnabled(false);
+ vp->setShadowsEnabled(false);
+ vp->setBackgroundColour(ColourValue(0, 0, 0));
+ //vp->setVisibilityMask( ... );
+
+ rtt->update();
+
+ // create "fog of war" texture
+ TexturePtr tex2 = TextureManager::getSingleton().createManual(
+ texture + "_fog",
+ ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
+ TEX_TYPE_2D,
+ xw*sFogOfWarResolution/sSize, yw*sFogOfWarResolution/sSize,
+ 0,
+ PF_A8R8G8B8,
+ TU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
+
+ // create a buffer to use for dynamic operations
+ std::vector buffer;
+ buffer.resize(sFogOfWarResolution*sFogOfWarResolution);
+
+ // initialize to (0, 0, 0, 1)
+ for (int p=0; pgetBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4);
+ tex2->getBuffer()->unlock();
+
+ mBuffers[texture] = buffer;
+
+ // save to cache for next time
+ //rtt->writeContentsToFile("./" + texture + ".jpg");
+ }
+ }
+
+
+ // re-enable fog
+ mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd);
+}
+
+void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Vector3& direction)
+{
+ if (sFogOfWarSkip != 0)
+ {
+ static int count=0;
+ if (++count % sFogOfWarSkip != 0)
+ return;
+ }
+
+ // retrieve the x,y grid coordinates the player is in
+ int x,y;
+ Vector2 pos(position.x, position.z);
+ if (!mInterior)
+ {
+ x = std::ceil(pos.x / sSize)-1;
+ y = std::ceil(-pos.y / sSize)-1;
+ mCellX = x;
+ mCellY = y;
+ }
+ else
+ {
+ Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
+ min *= 1.3;
+
+ x = std::ceil((pos.x - min.x)/sSize)-1;
+ y = std::ceil((pos.y - min.y)/sSize)-1;
+
+ mEnvironment->mWindowManager->setInteriorMapTexture(x,y);
+ }
+
+ // convert from world coordinates to texture UV coordinates
+ float u,v;
+ std::string texName;
+ if (!mInterior)
+ {
+ u = std::abs((pos.x - (sSize*x))/sSize);
+ v = 1-std::abs((pos.y + (sSize*y))/sSize);
+ texName = "Cell_"+coordStr(x,y);
+
+ }
+ else
+ {
+ Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
+ min *= 1.3;
+
+ u = (pos.x - min.x - sSize*x)/sSize;
+ v = (pos.y - min.y - sSize*y)/sSize;
+
+ texName = mInteriorName + "_" + coordStr(x,y);
+ }
+ mEnvironment->mWindowManager->setPlayerPos(u, v);
+ mEnvironment->mWindowManager->setPlayerDir(direction.x, -direction.z);
+
+ // explore radius (squared)
+ const float sqrExploreRadius = 0.01 * sFogOfWarResolution*sFogOfWarResolution;
+
+ // get the appropriate fog of war texture
+ TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog");
+ if (!tex.isNull())
+ {
+ // get its buffer
+ if (mBuffers.find(texName) == mBuffers.end()) return;
+ int i=0;
+ for (int texV = 0; texV> 24);
+ alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) );
+ mBuffers[texName][i] = (uint32) (alpha << 24);
+
+ ++i;
+ }
+ }
+
+ // copy to the texture
+ memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &mBuffers[texName][0], sFogOfWarResolution*sFogOfWarResolution*4);
+ tex->getBuffer()->unlock();
+ }
+}
diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp
new file mode 100644
index 0000000000..efbccf8848
--- /dev/null
+++ b/apps/openmw/mwrender/localmap.hpp
@@ -0,0 +1,100 @@
+#ifndef _GAME_RENDER_LOCALMAP_H
+#define _GAME_RENDER_LOCALMAP_H
+
+#include "../mwworld/ptr.hpp"
+
+#include
+
+namespace MWWorld
+{
+ class Environment;
+}
+
+namespace MWRender
+{
+ ///
+ /// \brief Local map rendering
+ ///
+ class LocalMap
+ {
+ public:
+ LocalMap(OEngine::Render::OgreRenderer*, MWWorld::Environment* env);
+ ~LocalMap();
+
+ /**
+ * Request the local map for an exterior cell.
+ * @remarks It will either be loaded from a disk cache,
+ * or rendered if it is not already cached.
+ * @param exterior cell
+ */
+ void requestMap (MWWorld::Ptr::CellStore* cell);
+
+ /**
+ * Request the local map for an interior cell.
+ * @remarks It will either be loaded from a disk cache,
+ * or rendered if it is not already cached.
+ * @param interior cell
+ * @param bounding box of the cell
+ */
+ void requestMap (MWWorld::Ptr::CellStore* cell,
+ Ogre::AxisAlignedBox bounds);
+
+ /**
+ * Set the position & direction of the player.
+ * @remarks This is used to draw a "fog of war" effect
+ * to hide areas on the map the player has not discovered yet.
+ * @param position (OGRE coordinates)
+ * @param view direction (OGRE coordinates)
+ */
+ void updatePlayer (const Ogre::Vector3& position, const Ogre::Vector3& direction);
+
+ /**
+ * Save the fog of war for the current cell to disk.
+ * @remarks This should be called before loading a
+ * new cell, as well as when the game is quit.
+ * @param current cell
+ */
+ void saveFogOfWar(MWWorld::Ptr::CellStore* cell);
+
+ private:
+ OEngine::Render::OgreRenderer* mRendering;
+ MWWorld::Environment* mEnvironment;
+
+ // 1024*1024 pixels for a cell
+ static const int sMapResolution = 1024;
+
+ // the dynamic texture is a bottleneck, so don't set this too high
+ static const int sFogOfWarResolution = 32;
+
+ // frames to skip before rendering fog of war
+ static const int sFogOfWarSkip = 2;
+
+ // size of a map segment (for exteriors, 1 cell)
+ static const int sSize = 8192;
+
+ Ogre::Camera* mCellCamera;
+
+ void render(const float x, const float y,
+ const float zlow, const float zhigh,
+ const float xw, const float yw,
+ const std::string& texture);
+
+ void saveTexture(const std::string& texname, const std::string& filename);
+
+ std::string coordStr(const int x, const int y);
+
+ // a buffer for the "fog of war" texture of the current cell.
+ // interior cells could be divided into multiple textures,
+ // so we store in a map.
+ std::map > mBuffers;
+
+ void deleteBuffers();
+
+ bool mInterior;
+ int mCellX, mCellY;
+ Ogre::AxisAlignedBox mBounds;
+ std::string mInteriorName;
+ };
+
+}
+#endif
diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp
index 717064ada5..e4e7212275 100644
--- a/apps/openmw/mwrender/objects.cpp
+++ b/apps/openmw/mwrender/objects.cpp
@@ -109,6 +109,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
// If it is set too low:
// - there will be too many batches.
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
+
+ mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
+ mBounds[ptr.getCell()].merge(ent->getBoundingBox());
}
else
{
@@ -116,6 +119,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
}
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
+ mBounds[ptr.getCell()].merge(insert->_getDerivedPosition());
mRenderer.getScene()->destroyEntity(ent);
}
@@ -202,6 +206,9 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store)
mRenderer.getScene()->destroyStaticGeometry (sg);
sg = 0;
}
+
+ if(mBounds.find(store) != mBounds.end())
+ mBounds.erase(store);
}
void Objects::buildStaticGeometry(ESMS::CellStore& cell)
@@ -212,3 +219,8 @@ void Objects::buildStaticGeometry(ESMS::CellStore& cell)
sg->build();
}
}
+
+Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
+{
+ return mBounds[cell];
+}
diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp
index d58455b9f3..1ca81331d1 100644
--- a/apps/openmw/mwrender/objects.hpp
+++ b/apps/openmw/mwrender/objects.hpp
@@ -14,6 +14,7 @@ class Objects{
OEngine::Render::OgreRenderer &mRenderer;
std::map mCellSceneNodes;
std::map mStaticGeometry;
+ std::map mBounds;
Ogre::SceneNode* mMwRoot;
bool mIsStatic;
static int uniqueID;
@@ -42,6 +43,9 @@ public:
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
void insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius);
+ Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*);
+ ///< get a bounding box that encloses all objects in the specified cell
+
bool deleteObject (const MWWorld::Ptr& ptr);
///< \return found?
diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp
index 4f84d90a95..e2aea19c6e 100644
--- a/apps/openmw/mwrender/renderingmanager.cpp
+++ b/apps/openmw/mwrender/renderingmanager.cpp
@@ -55,6 +55,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
mSun = 0;
+
+ mLocalMap = new MWRender::LocalMap(&mRendering, &environment);
}
RenderingManager::~RenderingManager ()
@@ -62,6 +64,7 @@ RenderingManager::~RenderingManager ()
//TODO: destroy mSun?
delete mPlayer;
delete mSkyManager;
+ delete mLocalMap;
}
MWRender::SkyManager* RenderingManager::getSkyManager()
@@ -137,6 +140,8 @@ void RenderingManager::update (float duration){
mSkyManager->update(duration);
mRendering.update(duration);
+
+ mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealDirection() );
}
void RenderingManager::skyEnable ()
@@ -327,4 +332,17 @@ void RenderingManager::setGlare(bool glare)
mSkyManager->setGlare(glare);
}
+void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell)
+{
+ if (!(cell->cell->data.flags & ESM::Cell::Interior))
+ mLocalMap->requestMap(cell);
+ else
+ mLocalMap->requestMap(cell, mObjects.getDimensions(cell));
+}
+
+void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell)
+{
+ mLocalMap->saveFogOfWar(cell);
+}
+
} // namespace
diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp
index d84ee43e00..78a1d2fdb7 100644
--- a/apps/openmw/mwrender/renderingmanager.hpp
+++ b/apps/openmw/mwrender/renderingmanager.hpp
@@ -24,6 +24,7 @@
#include "objects.hpp"
#include "actors.hpp"
#include "player.hpp"
+#include "localmap.hpp"
namespace Ogre
{
@@ -75,6 +76,9 @@ class RenderingManager: private RenderingInterface {
/// when rebatching is needed and update automatically at the end of each frame.
void cellAdded (MWWorld::Ptr::CellStore *store);
+ void preCellChange (MWWorld::Ptr::CellStore* store);
+ ///< this event is fired immediately before changing cell
+
void addObject (const MWWorld::Ptr& ptr);
void removeObject (const MWWorld::Ptr& ptr);
@@ -102,6 +106,9 @@ class RenderingManager: private RenderingInterface {
int skyGetSecundaPhase() const;
void skySetMoonColour (bool red);
void configureAmbient(ESMS::CellStore &mCell);
+
+ void requestMap (MWWorld::Ptr::CellStore* cell);
+ ///< request the local map for a cell
/// configure fog according to cell
void configureFog(ESMS::CellStore &mCell);
@@ -148,6 +155,8 @@ class RenderingManager: private RenderingInterface {
MWRender::Player *mPlayer;
MWRender::Debugging mDebugging;
+
+ MWRender::LocalMap* mLocalMap;
};
}
diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp
index a747b9be04..a41bc21e0f 100644
--- a/apps/openmw/mwrender/sky.cpp
+++ b/apps/openmw/mwrender/sky.cpp
@@ -254,7 +254,7 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType)
// Get a pointer to the vertex colour
ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex );
- unsigned char alpha;
+ unsigned char alpha=0;
if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row
else if (meshType == 1)
{
@@ -292,10 +292,40 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType)
ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock();
}
-SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environment* env) :
- mGlareFade(0), mGlareEnabled(false)
+SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environment* env)
+ : mEnvironment(env)
+ , mHour(0.0f)
+ , mDay(0)
+ , mMonth(0)
+ , mSun(NULL)
+ , mSunGlare(NULL)
+ , mMasser(NULL)
+ , mSecunda(NULL)
+ , mViewport(NULL)
+ , mRootNode(NULL)
+ , mSceneMgr(NULL)
+ , mAtmosphereDay(NULL)
+ , mAtmosphereNight(NULL)
+ , mCloudMaterial()
+ , mAtmosphereMaterial()
+ , mCloudFragmentShader()
+ , mClouds()
+ , mNextClouds()
+ , mCloudBlendFactor(0.0f)
+ , mCloudOpacity(0.0f)
+ , mCloudSpeed(0.0f)
+ , mStarsOpacity(0.0f)
+ , mThunderOverlay(NULL)
+ , mThunderTextureUnit(NULL)
+ , mRemainingTransitionTime(0.0f)
+ , mGlareFade(0.0f)
+ , mEnabled(true)
+ , mGlareEnabled(true)
+ , mSunEnabled(true)
+ , mMasserEnabled(true)
+ , mSecundaEnabled(true)
{
- mEnvironment = env;
+
mViewport = pCamera->getViewport();
mSceneMgr = pMwRoot->getCreator();
mRootNode = pCamera->getParentSceneNode()->createChildSceneNode();
@@ -446,6 +476,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
vshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
+ mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram("");
// Clouds
NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif");
diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp
new file mode 100644
index 0000000000..9298bf8488
--- /dev/null
+++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp
@@ -0,0 +1,407 @@
+#ifdef OPENMW_USE_FFMPEG
+
+#include "ffmpeg_decoder.hpp"
+
+
+namespace MWSound
+{
+
+static void fail(const std::string &msg)
+{ throw std::runtime_error("FFmpeg exception: "+msg); }
+
+
+struct PacketList {
+ AVPacket pkt;
+ PacketList *next;
+};
+
+struct FFmpeg_Decoder::MyStream {
+ AVCodecContext *mCodecCtx;
+ int mStreamIdx;
+
+ PacketList *mPackets;
+
+ char *mDecodedData;
+ size_t mDecodedDataSize;
+
+ FFmpeg_Decoder *mParent;
+
+ void clearPackets();
+ void *getAVAudioData(size_t *length);
+ size_t readAVAudioData(void *data, size_t length);
+};
+
+
+int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+ return stream->read(buf, buf_size);
+}
+
+int FFmpeg_Decoder::writePacket(void *user_data, uint8_t *buf, int buf_size)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+ return stream->write(buf, buf_size);
+}
+
+int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+
+ whence &= ~AVSEEK_FORCE;
+ if(whence == AVSEEK_SIZE)
+ return stream->size();
+ if(whence == SEEK_SET)
+ stream->seek(offset);
+ else if(whence == SEEK_CUR)
+ stream->seek(stream->tell()+offset);
+ else if(whence == SEEK_END)
+ stream->seek(stream->size()+offset);
+ else
+ return -1;
+
+ return stream->tell();
+}
+
+
+/* Used by getAV*Data to search for more compressed data, and buffer it in the
+ * correct stream. It won't buffer data for streams that the app doesn't have a
+ * handle for. */
+bool FFmpeg_Decoder::getNextPacket(int streamidx)
+{
+ PacketList *packet;
+
+ packet = (PacketList*)av_malloc(sizeof(*packet));
+ packet->next = NULL;
+
+next_packet:
+ while(av_read_frame(mFormatCtx, &packet->pkt) >= 0)
+ {
+ std::vector::iterator iter = mStreams.begin();
+
+ /* Check each stream the user has a handle for, looking for the one
+ * this packet belongs to */
+ while(iter != mStreams.end())
+ {
+ if((*iter)->mStreamIdx == packet->pkt.stream_index)
+ {
+ PacketList **last;
+
+ last = &(*iter)->mPackets;
+ while(*last != NULL)
+ last = &(*last)->next;
+
+ *last = packet;
+ if((*iter)->mStreamIdx == streamidx)
+ return true;
+
+ packet = (PacketList*)av_malloc(sizeof(*packet));
+ packet->next = NULL;
+ goto next_packet;
+ }
+ iter++;
+ }
+ /* Free the packet and look for another */
+ av_free_packet(&packet->pkt);
+ }
+ av_free(packet);
+
+ return false;
+}
+
+void FFmpeg_Decoder::MyStream::clearPackets()
+{
+ while(mPackets)
+ {
+ PacketList *self = mPackets;
+ mPackets = self->next;
+
+ av_free_packet(&self->pkt);
+ av_free(self);
+ }
+}
+
+void *FFmpeg_Decoder::MyStream::getAVAudioData(size_t *length)
+{
+ int size;
+ int len;
+
+ if(length) *length = 0;
+ if(mCodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
+ return NULL;
+
+ mDecodedDataSize = 0;
+
+next_packet:
+ if(!mPackets && !mParent->getNextPacket(mStreamIdx))
+ return NULL;
+
+ /* Decode some data, and check for errors */
+ size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ while((len=avcodec_decode_audio3(mCodecCtx, (int16_t*)mDecodedData, &size,
+ &mPackets->pkt)) == 0)
+ {
+ PacketList *self;
+
+ if(size > 0)
+ break;
+
+ /* Packet went unread and no data was given? Drop it and try the next,
+ * I guess... */
+ self = mPackets;
+ mPackets = self->next;
+
+ av_free_packet(&self->pkt);
+ av_free(self);
+
+ if(!mPackets)
+ goto next_packet;
+
+ size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ }
+
+ if(len < 0)
+ return NULL;
+
+ if(len < mPackets->pkt.size)
+ {
+ /* Move the unread data to the front and clear the end bits */
+ int remaining = mPackets->pkt.size - len;
+ memmove(mPackets->pkt.data, &mPackets->pkt.data[len], remaining);
+ memset(&mPackets->pkt.data[remaining], 0, mPackets->pkt.size - remaining);
+ mPackets->pkt.size -= len;
+ }
+ else
+ {
+ PacketList *self;
+
+ self = mPackets;
+ mPackets = self->next;
+
+ av_free_packet(&self->pkt);
+ av_free(self);
+ }
+
+ if(size == 0)
+ goto next_packet;
+
+ /* Set the output buffer size */
+ mDecodedDataSize = size;
+ if(length) *length = mDecodedDataSize;
+
+ return mDecodedData;
+}
+
+size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length)
+{
+ size_t dec = 0;
+
+ while(dec < length)
+ {
+ /* If there's no decoded data, find some */
+ if(mDecodedDataSize == 0)
+ {
+ if(getAVAudioData(NULL) == NULL)
+ break;
+ }
+
+ if(mDecodedDataSize > 0)
+ {
+ /* Get the amount of bytes remaining to be written, and clamp to
+ * the amount of decoded data we have */
+ size_t rem = length-dec;
+ if(rem > mDecodedDataSize)
+ rem = mDecodedDataSize;
+
+ /* Copy the data to the app's buffer and increment */
+ if(data != NULL)
+ {
+ memcpy(data, mDecodedData, rem);
+ data = (char*)data + rem;
+ }
+ dec += rem;
+
+ /* If there's any decoded data left, move it to the front of the
+ * buffer for next time */
+ if(rem < mDecodedDataSize)
+ memmove(mDecodedData, &mDecodedData[rem], mDecodedDataSize - rem);
+ mDecodedDataSize -= rem;
+ }
+ }
+
+ /* Return the number of bytes we were able to get */
+ return dec;
+}
+
+
+
+void FFmpeg_Decoder::open(const std::string &fname)
+{
+ close();
+ mDataStream = mResourceMgr.openResource(fname);
+
+ if((mFormatCtx=avformat_alloc_context()) == NULL)
+ fail("Failed to allocate context");
+
+ mFormatCtx->pb = avio_alloc_context(NULL, 0, 0, this, readPacket, writePacket, seek);
+ if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), NULL, NULL) != 0)
+ {
+ avformat_free_context(mFormatCtx);
+ mFormatCtx = NULL;
+ fail("Failed to allocate input stream");
+ }
+
+ try
+ {
+ if(avformat_find_stream_info(mFormatCtx, NULL) < 0)
+ fail("Failed to find stream info in "+fname);
+
+ for(size_t j = 0;j < mFormatCtx->nb_streams;j++)
+ {
+ if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ {
+ std::auto_ptr stream(new MyStream);
+ stream->mCodecCtx = mFormatCtx->streams[j]->codec;
+ stream->mStreamIdx = j;
+ stream->mPackets = NULL;
+
+ AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id);
+ if(!codec)
+ {
+ std::stringstream ss("No codec found for id ");
+ ss << stream->mCodecCtx->codec_id;
+ fail(ss.str());
+ }
+ if(avcodec_open(stream->mCodecCtx, codec) < 0)
+ fail("Failed to open audio codec " + std::string(codec->long_name));
+
+ stream->mDecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
+ stream->mDecodedDataSize = 0;
+
+ stream->mParent = this;
+ mStreams.push_back(stream.release());
+ break;
+ }
+ }
+ if(mStreams.empty())
+ fail("No audio streams in "+fname);
+ }
+ catch(std::exception &e)
+ {
+ av_close_input_file(mFormatCtx);
+ mFormatCtx = NULL;
+ throw;
+ }
+}
+
+void FFmpeg_Decoder::close()
+{
+ while(!mStreams.empty())
+ {
+ MyStream *stream = mStreams.front();
+
+ stream->clearPackets();
+ avcodec_close(stream->mCodecCtx);
+ av_free(stream->mDecodedData);
+ delete stream;
+
+ mStreams.erase(mStreams.begin());
+ }
+ if(mFormatCtx)
+ av_close_input_file(mFormatCtx);
+ mFormatCtx = NULL;
+
+ mDataStream.setNull();
+}
+
+void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
+{
+ if(mStreams.empty())
+ fail("No audio stream info");
+
+ MyStream *stream = mStreams[0];
+ if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8)
+ *type = SampleType_UInt8;
+ else if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S16)
+ *type = SampleType_Int16;
+ else
+ fail(std::string("Unsupported sample format: ")+
+ av_get_sample_fmt_name(stream->mCodecCtx->sample_fmt));
+
+ if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO)
+ *chans = ChannelConfig_Mono;
+ else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO)
+ *chans = ChannelConfig_Stereo;
+ else if(stream->mCodecCtx->channel_layout == 0)
+ {
+ /* Unknown channel layout. Try to guess. */
+ if(stream->mCodecCtx->channels == 1)
+ *chans = ChannelConfig_Mono;
+ else if(stream->mCodecCtx->channels == 2)
+ *chans = ChannelConfig_Stereo;
+ else
+ {
+ std::stringstream sstr("Unsupported raw channel count: ");
+ sstr << stream->mCodecCtx->channels;
+ fail(sstr.str());
+ }
+ }
+ else
+ {
+ char str[1024];
+ av_get_channel_layout_string(str, sizeof(str), stream->mCodecCtx->channels,
+ stream->mCodecCtx->channel_layout);
+ fail(std::string("Unsupported channel layout: ")+str);
+ }
+
+ *samplerate = stream->mCodecCtx->sample_rate;
+}
+
+size_t FFmpeg_Decoder::read(char *buffer, size_t bytes)
+{
+ if(mStreams.empty())
+ fail("No audio streams");
+
+ return mStreams.front()->readAVAudioData(buffer, bytes);
+}
+
+void FFmpeg_Decoder::readAll(std::vector &output)
+{
+ if(mStreams.empty())
+ fail("No audio streams");
+ MyStream *stream = mStreams.front();
+ char *inbuf;
+ size_t got;
+
+ while((inbuf=(char*)stream->getAVAudioData(&got)) != NULL && got > 0)
+ output.insert(output.end(), inbuf, inbuf+got);
+}
+
+void FFmpeg_Decoder::rewind()
+{
+ av_seek_frame(mFormatCtx, -1, 0, 0);
+ std::for_each(mStreams.begin(), mStreams.end(), std::mem_fun(&MyStream::clearPackets));
+}
+
+FFmpeg_Decoder::FFmpeg_Decoder() : mFormatCtx(NULL)
+{
+ static bool done_init = false;
+
+ /* We need to make sure ffmpeg is initialized. Optionally silence warning
+ * output from the lib */
+ if(!done_init)
+ {
+ av_register_all();
+ av_log_set_level(AV_LOG_ERROR);
+ done_init = true;
+ }
+}
+
+FFmpeg_Decoder::~FFmpeg_Decoder()
+{
+ close();
+}
+
+}
+
+#endif
diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp
new file mode 100644
index 0000000000..4344397c70
--- /dev/null
+++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp
@@ -0,0 +1,59 @@
+#ifndef GAME_SOUND_FFMPEG_DECODER_H
+#define GAME_SOUND_FFMPEG_DECODER_H
+
+#include
+
+// FIXME: This can't be right? The headers refuse to build without UINT64_C,
+// which only gets defined in stdint.h in either C99 mode or with this macro
+// defined...
+#define __STDC_CONSTANT_MACROS
+#include
+extern "C"
+{
+#include
+#include
+}
+
+#include "sound_decoder.hpp"
+
+
+namespace MWSound
+{
+ class FFmpeg_Decoder : public Sound_Decoder
+ {
+ AVFormatContext *mFormatCtx;
+
+ struct MyStream;
+ std::vector mStreams;
+
+ bool getNextPacket(int streamidx);
+
+ Ogre::DataStreamPtr mDataStream;
+ static int readPacket(void *user_data, uint8_t *buf, int buf_size);
+ static int writePacket(void *user_data, uint8_t *buf, int buf_size);
+ static int64_t seek(void *user_data, int64_t offset, int whence);
+
+ virtual void open(const std::string &fname);
+ virtual void close();
+
+ virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
+
+ virtual size_t read(char *buffer, size_t bytes);
+ virtual void readAll(std::vector &output);
+ virtual void rewind();
+
+ FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs);
+ FFmpeg_Decoder(const FFmpeg_Decoder &rhs);
+
+ FFmpeg_Decoder();
+ public:
+ virtual ~FFmpeg_Decoder();
+
+ friend class SoundManager;
+ };
+#ifndef DEFAULT_DECODER
+#define DEFAULT_DECODER (::MWSound::FFmpeg_Decoder)
+#endif
+};
+
+#endif
diff --git a/apps/openmw/mwsound/mpgsnd_decoder.cpp b/apps/openmw/mwsound/mpgsnd_decoder.cpp
new file mode 100644
index 0000000000..9b91b4e74e
--- /dev/null
+++ b/apps/openmw/mwsound/mpgsnd_decoder.cpp
@@ -0,0 +1,237 @@
+#ifdef OPENMW_USE_MPG123
+
+#include
+#include
+
+#include "mpgsnd_decoder.hpp"
+
+
+static void fail(const std::string &msg)
+{ throw std::runtime_error("MpgSnd exception: "+msg); }
+
+namespace MWSound
+{
+
+//
+// libSndFile io callbacks
+//
+sf_count_t MpgSnd_Decoder::ogresf_get_filelen(void *user_data)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+ return stream->size();
+}
+
+sf_count_t MpgSnd_Decoder::ogresf_seek(sf_count_t offset, int whence, void *user_data)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+
+ if(whence == SEEK_CUR)
+ stream->seek(stream->tell()+offset);
+ else if(whence == SEEK_SET)
+ stream->seek(offset);
+ else if(whence == SEEK_END)
+ stream->seek(stream->size()+offset);
+ else
+ return -1;
+
+ return stream->tell();
+}
+
+sf_count_t MpgSnd_Decoder::ogresf_read(void *ptr, sf_count_t count, void *user_data)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+ return stream->read(ptr, count);
+}
+
+sf_count_t MpgSnd_Decoder::ogresf_write(const void*, sf_count_t, void*)
+{ return -1; }
+
+sf_count_t MpgSnd_Decoder::ogresf_tell(void *user_data)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+ return stream->tell();
+}
+
+//
+// libmpg13 io callbacks
+//
+ssize_t MpgSnd_Decoder::ogrempg_read(void *user_data, void *ptr, size_t count)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+ return stream->read(ptr, count);
+}
+
+off_t MpgSnd_Decoder::ogrempg_lseek(void *user_data, off_t offset, int whence)
+{
+ Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream;
+
+ if(whence == SEEK_CUR)
+ stream->seek(stream->tell()+offset);
+ else if(whence == SEEK_SET)
+ stream->seek(offset);
+ else if(whence == SEEK_END)
+ stream->seek(stream->size()+offset);
+ else
+ return -1;
+
+ return stream->tell();
+}
+
+
+void MpgSnd_Decoder::open(const std::string &fname)
+{
+ close();
+ mDataStream = mResourceMgr.openResource(fname);
+
+ SF_VIRTUAL_IO streamIO = {
+ ogresf_get_filelen, ogresf_seek,
+ ogresf_read, ogresf_write, ogresf_tell
+ };
+ mSndFile = sf_open_virtual(&streamIO, SFM_READ, &mSndInfo, this);
+ if(mSndFile)
+ {
+ if(mSndInfo.channels == 1)
+ mChanConfig = ChannelConfig_Mono;
+ else if(mSndInfo.channels == 2)
+ mChanConfig = ChannelConfig_Stereo;
+ else
+ {
+ sf_close(mSndFile);
+ mSndFile = NULL;
+ fail("Unsupported channel count in "+fname);
+ }
+ mSampleRate = mSndInfo.samplerate;
+ return;
+ }
+ mDataStream->seek(0);
+
+ mMpgFile = mpg123_new(NULL, NULL);
+ if(mMpgFile && mpg123_replace_reader_handle(mMpgFile, ogrempg_read, ogrempg_lseek, NULL) == MPG123_OK &&
+ mpg123_open_handle(mMpgFile, this) == MPG123_OK)
+ {
+ try
+ {
+ int encoding, channels;
+ long rate;
+ if(mpg123_getformat(mMpgFile, &rate, &channels, &encoding) != MPG123_OK)
+ fail("Failed to get audio format");
+ if(encoding != MPG123_ENC_SIGNED_16)
+ fail("Unsupported encoding in "+fname);
+ if(channels != 1 && channels != 2)
+ fail("Unsupported channel count in "+fname);
+ mChanConfig = ((channels==2)?ChannelConfig_Stereo:ChannelConfig_Mono);
+ mSampleRate = rate;
+ return;
+ }
+ catch(std::exception &e)
+ {
+ mpg123_close(mMpgFile);
+ mpg123_delete(mMpgFile);
+ mMpgFile = NULL;
+ throw;
+ }
+ mpg123_close(mMpgFile);
+ }
+ if(mMpgFile)
+ mpg123_delete(mMpgFile);
+ mMpgFile = NULL;
+
+ fail("Unsupported file type: "+fname);
+}
+
+void MpgSnd_Decoder::close()
+{
+ if(mSndFile)
+ sf_close(mSndFile);
+ mSndFile = NULL;
+
+ if(mMpgFile)
+ {
+ mpg123_close(mMpgFile);
+ mpg123_delete(mMpgFile);
+ mMpgFile = NULL;
+ }
+
+ mDataStream.setNull();
+}
+
+void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
+{
+ if(!mSndFile && !mMpgFile)
+ fail("No open file");
+
+ *samplerate = mSampleRate;
+ *chans = mChanConfig;
+ *type = SampleType_Int16;
+}
+
+size_t MpgSnd_Decoder::read(char *buffer, size_t bytes)
+{
+ size_t got = 0;
+
+ if(mSndFile)
+ {
+ got = sf_read_short(mSndFile, (short*)buffer, bytes/2)*2;
+ }
+ else if(mMpgFile)
+ {
+ int err;
+ err = mpg123_read(mMpgFile, (unsigned char*)buffer, bytes, &got);
+ if(err != MPG123_OK && err != MPG123_DONE)
+ fail("Failed to read from file");
+ }
+ return got;
+}
+
+void MpgSnd_Decoder::readAll(std::vector &output)
+{
+ if(mSndFile && mSndInfo.frames > 0)
+ {
+ size_t pos = output.size();
+ output.resize(pos + mSndInfo.frames*mSndInfo.channels*2);
+ sf_readf_short(mSndFile, (short*)(output.data()+pos), mSndInfo.frames);
+ return;
+ }
+ // Fallback in case we don't know the total already
+ Sound_Decoder::readAll(output);
+}
+
+void MpgSnd_Decoder::rewind()
+{
+ if(!mSndFile && !mMpgFile)
+ fail("No open file");
+
+ if(mSndFile)
+ {
+ if(sf_seek(mSndFile, 0, SEEK_SET) == -1)
+ fail("seek failed");
+ }
+ else if(mMpgFile)
+ {
+ if(mpg123_seek(mMpgFile, 0, SEEK_SET) < 0)
+ fail("seek failed");
+ }
+}
+
+MpgSnd_Decoder::MpgSnd_Decoder()
+ : mSndInfo()
+ , mSndFile(NULL)
+ , mMpgFile(NULL)
+ , mDataStream()
+ , mChanConfig(ChannelConfig_Stereo)
+ , mSampleRate(0)
+{
+ static bool initdone = false;
+ if(!initdone)
+ mpg123_init();
+ initdone = true;
+}
+
+MpgSnd_Decoder::~MpgSnd_Decoder()
+{
+ close();
+}
+
+}
+
+#endif
diff --git a/apps/openmw/mwsound/mpgsnd_decoder.hpp b/apps/openmw/mwsound/mpgsnd_decoder.hpp
new file mode 100644
index 0000000000..870773edc5
--- /dev/null
+++ b/apps/openmw/mwsound/mpgsnd_decoder.hpp
@@ -0,0 +1,57 @@
+#ifndef GAME_SOUND_MPGSND_DECODER_H
+#define GAME_SOUND_MPGSND_DECODER_H
+
+#include
+
+#include
+
+#include "mpg123.h"
+#include "sndfile.h"
+
+#include "sound_decoder.hpp"
+
+
+namespace MWSound
+{
+ class MpgSnd_Decoder : public Sound_Decoder
+ {
+ SF_INFO mSndInfo;
+ SNDFILE *mSndFile;
+ mpg123_handle *mMpgFile;
+
+ Ogre::DataStreamPtr mDataStream;
+ static sf_count_t ogresf_get_filelen(void *user_data);
+ static sf_count_t ogresf_seek(sf_count_t offset, int whence, void *user_data);
+ static sf_count_t ogresf_read(void *ptr, sf_count_t count, void *user_data);
+ static sf_count_t ogresf_write(const void*, sf_count_t, void*);
+ static sf_count_t ogresf_tell(void *user_data);
+ static ssize_t ogrempg_read(void*, void*, size_t);
+ static off_t ogrempg_lseek(void*, off_t, int);
+
+ ChannelConfig mChanConfig;
+ int mSampleRate;
+
+ virtual void open(const std::string &fname);
+ virtual void close();
+
+ virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
+
+ virtual size_t read(char *buffer, size_t bytes);
+ virtual void readAll(std::vector &output);
+ virtual void rewind();
+
+ MpgSnd_Decoder& operator=(const MpgSnd_Decoder &rhs);
+ MpgSnd_Decoder(const MpgSnd_Decoder &rhs);
+
+ MpgSnd_Decoder();
+ public:
+ virtual ~MpgSnd_Decoder();
+
+ friend class SoundManager;
+ };
+#ifndef DEFAULT_DECODER
+#define DEFAULT_DECODER (::MWSound::MpgSnd_Decoder)
+#endif
+};
+
+#endif
diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp
new file mode 100644
index 0000000000..edd923f433
--- /dev/null
+++ b/apps/openmw/mwsound/openal_output.cpp
@@ -0,0 +1,774 @@
+#include
+#include
+#include
+#include
+
+#include
+
+#include "openal_output.hpp"
+#include "sound_decoder.hpp"
+#include "sound.hpp"
+#include "soundmanager.hpp"
+
+#ifndef ALC_ALL_DEVICES_SPECIFIER
+#define ALC_ALL_DEVICES_SPECIFIER 0x1013
+#endif
+
+
+namespace MWSound
+{
+
+static void fail(const std::string &msg)
+{ throw std::runtime_error("OpenAL exception: " + msg); }
+
+static void throwALCerror(ALCdevice *device)
+{
+ ALCenum err = alcGetError(device);
+ if(err != ALC_NO_ERROR)
+ fail(alcGetString(device, err));
+}
+
+static void throwALerror()
+{
+ ALenum err = alGetError();
+ if(err != AL_NO_ERROR)
+ fail(alGetString(err));
+}
+
+
+static ALenum getALFormat(ChannelConfig chans, SampleType type)
+{
+ static const struct {
+ ALenum format;
+ ChannelConfig chans;
+ SampleType type;
+ } fmtlist[] = {
+ { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 },
+ { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 },
+ { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 },
+ { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 },
+ };
+ static const size_t fmtlistsize = sizeof(fmtlist)/sizeof(fmtlist[0]);
+
+ for(size_t i = 0;i < fmtlistsize;i++)
+ {
+ if(fmtlist[i].chans == chans && fmtlist[i].type == type)
+ return fmtlist[i].format;
+ }
+ fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")");
+ return AL_NONE;
+}
+
+//
+// A streaming OpenAL sound.
+//
+class OpenAL_SoundStream : public Sound
+{
+ static const ALuint sNumBuffers = 6;
+ static const ALfloat sBufferLength;
+
+ OpenAL_Output &mOutput;
+
+ ALuint mSource;
+ ALuint mBuffers[sNumBuffers];
+
+ ALenum mFormat;
+ ALsizei mSampleRate;
+ ALuint mBufferSize;
+
+ DecoderPtr mDecoder;
+
+ volatile bool mIsFinished;
+
+ OpenAL_SoundStream(const OpenAL_SoundStream &rhs);
+ OpenAL_SoundStream& operator=(const OpenAL_SoundStream &rhs);
+
+public:
+ OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder);
+ virtual ~OpenAL_SoundStream();
+
+ virtual void stop();
+ virtual bool isPlaying();
+ virtual void update(const float *pos);
+
+ void play();
+ bool process();
+};
+
+const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f;
+
+//
+// A background streaming thread (keeps active streams processed)
+//
+struct OpenAL_Output::StreamThread {
+ typedef std::vector StreamVec;
+ StreamVec mStreams;
+ boost::mutex mMutex;
+ boost::thread mThread;
+
+ StreamThread()
+ : mThread(boost::ref(*this))
+ {
+ }
+ ~StreamThread()
+ {
+ mThread.interrupt();
+ }
+
+ // boost::thread entry point
+ void operator()()
+ {
+ while(1)
+ {
+ mMutex.lock();
+ StreamVec::iterator iter = mStreams.begin();
+ while(iter != mStreams.end())
+ {
+ if((*iter)->process() == false)
+ iter = mStreams.erase(iter);
+ else
+ iter++;
+ }
+ mMutex.unlock();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+ }
+ }
+
+ void add(OpenAL_SoundStream *stream)
+ {
+ mMutex.lock();
+ if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end())
+ mStreams.push_back(stream);
+ mMutex.unlock();
+ }
+
+ void remove(OpenAL_SoundStream *stream)
+ {
+ mMutex.lock();
+ StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream);
+ if(iter != mStreams.end())
+ mStreams.erase(iter);
+ mMutex.unlock();
+ }
+
+ void removeAll()
+ {
+ mMutex.lock();
+ mStreams.clear();
+ mMutex.unlock();
+ }
+
+private:
+ StreamThread(const StreamThread &rhs);
+ StreamThread& operator=(const StreamThread &rhs);
+};
+
+
+OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder)
+ : mOutput(output), mSource(src), mDecoder(decoder), mIsFinished(true)
+{
+ throwALerror();
+
+ alGenBuffers(sNumBuffers, mBuffers);
+ throwALerror();
+ try
+ {
+ int srate;
+ ChannelConfig chans;
+ SampleType type;
+
+ mDecoder->getInfo(&srate, &chans, &type);
+ mFormat = getALFormat(chans, type);
+ mSampleRate = srate;
+
+ mBufferSize = static_cast(sBufferLength*srate);
+ mBufferSize = framesToBytes(mBufferSize, chans, type);
+ }
+ catch(std::exception &e)
+ {
+ mOutput.mFreeSources.push_back(mSource);
+ alDeleteBuffers(sNumBuffers, mBuffers);
+ alGetError();
+ throw;
+ }
+}
+OpenAL_SoundStream::~OpenAL_SoundStream()
+{
+ mOutput.mStreamThread->remove(this);
+
+ alSourceStop(mSource);
+ alSourcei(mSource, AL_BUFFER, 0);
+
+ mOutput.mFreeSources.push_back(mSource);
+ alDeleteBuffers(sNumBuffers, mBuffers);
+ alGetError();
+
+ mDecoder->close();
+}
+
+void OpenAL_SoundStream::play()
+{
+ std::vector data(mBufferSize);
+
+ alSourceStop(mSource);
+ alSourcei(mSource, AL_BUFFER, 0);
+ throwALerror();
+
+ for(ALuint i = 0;i < sNumBuffers;i++)
+ {
+ size_t got;
+ got = mDecoder->read(data.data(), data.size());
+ alBufferData(mBuffers[i], mFormat, data.data(), got, mSampleRate);
+ }
+ throwALerror();
+
+ alSourceQueueBuffers(mSource, sNumBuffers, mBuffers);
+ alSourcePlay(mSource);
+ throwALerror();
+
+ mIsFinished = false;
+ mOutput.mStreamThread->add(this);
+}
+
+void OpenAL_SoundStream::stop()
+{
+ mOutput.mStreamThread->remove(this);
+ mIsFinished = true;
+
+ alSourceStop(mSource);
+ alSourcei(mSource, AL_BUFFER, 0);
+ throwALerror();
+
+ mDecoder->rewind();
+}
+
+bool OpenAL_SoundStream::isPlaying()
+{
+ ALint state;
+
+ alGetSourcei(mSource, AL_SOURCE_STATE, &state);
+ throwALerror();
+
+ if(state == AL_PLAYING)
+ return true;
+ return !mIsFinished;
+}
+
+void OpenAL_SoundStream::update(const float *pos)
+{
+ alSource3f(mSource, AL_POSITION, pos[0], pos[2], -pos[1]);
+ alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
+ alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+ throwALerror();
+}
+
+bool OpenAL_SoundStream::process()
+{
+ bool finished = mIsFinished;
+ ALint processed, state;
+
+ alGetSourcei(mSource, AL_SOURCE_STATE, &state);
+ alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
+ throwALerror();
+
+ if(processed > 0)
+ {
+ std::vector data(mBufferSize);
+ do {
+ ALuint bufid;
+ size_t got;
+
+ alSourceUnqueueBuffers(mSource, 1, &bufid);
+ processed--;
+
+ if(finished)
+ continue;
+
+ got = mDecoder->read(data.data(), data.size());
+ finished = (got < data.size());
+ if(got > 0)
+ {
+ alBufferData(bufid, mFormat, data.data(), got, mSampleRate);
+ alSourceQueueBuffers(mSource, 1, &bufid);
+ }
+ } while(processed > 0);
+ throwALerror();
+ }
+
+ if(state != AL_PLAYING && state != AL_PAUSED)
+ {
+ ALint queued;
+
+ alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
+ throwALerror();
+ if(queued > 0)
+ {
+ alSourcePlay(mSource);
+ throwALerror();
+ }
+ }
+
+ mIsFinished = finished;
+ return !finished;
+}
+
+//
+// A regular OpenAL sound
+//
+class OpenAL_Sound : public Sound
+{
+ OpenAL_Output &mOutput;
+
+ ALuint mSource;
+ ALuint mBuffer;
+
+ OpenAL_Sound(const OpenAL_Sound &rhs);
+ OpenAL_Sound& operator=(const OpenAL_Sound &rhs);
+
+public:
+ OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf);
+ virtual ~OpenAL_Sound();
+
+ virtual void stop();
+ virtual bool isPlaying();
+ virtual void update(const float *pos);
+};
+
+OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf)
+ : mOutput(output), mSource(src), mBuffer(buf)
+{
+}
+OpenAL_Sound::~OpenAL_Sound()
+{
+ alSourceStop(mSource);
+ alSourcei(mSource, AL_BUFFER, 0);
+
+ mOutput.mFreeSources.push_back(mSource);
+ mOutput.bufferFinished(mBuffer);
+}
+
+void OpenAL_Sound::stop()
+{
+ alSourceStop(mSource);
+ throwALerror();
+}
+
+bool OpenAL_Sound::isPlaying()
+{
+ ALint state;
+
+ alGetSourcei(mSource, AL_SOURCE_STATE, &state);
+ throwALerror();
+
+ return state==AL_PLAYING;
+}
+
+void OpenAL_Sound::update(const float *pos)
+{
+ alSource3f(mSource, AL_POSITION, pos[0], pos[2], -pos[1]);
+ alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
+ alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+ throwALerror();
+}
+
+
+//
+// An OpenAL output device
+//
+std::vector OpenAL_Output::enumerate()
+{
+ std::vector devlist;
+ const ALCchar *devnames;
+
+ if(alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
+ devnames = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
+ else
+ devnames = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
+ while(devnames && *devnames)
+ {
+ devlist.push_back(devnames);
+ devnames += strlen(devnames)+1;
+ }
+ return devlist;
+}
+
+void OpenAL_Output::init(const std::string &devname)
+{
+ if(mDevice || mContext)
+ fail("Device already open");
+
+ mDevice = alcOpenDevice(devname.c_str());
+ if(!mDevice)
+ {
+ if(devname.empty())
+ fail("Failed to open default device");
+ else
+ fail("Failed to open \""+devname+"\"");
+ }
+ if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT"))
+ std::cout << "Opened \""<removeAll();
+
+ if(!mFreeSources.empty())
+ {
+ alDeleteSources(mFreeSources.size(), mFreeSources.data());
+ mFreeSources.clear();
+ }
+
+ mBufferRefs.clear();
+ mUnusedBuffers.clear();
+ while(!mBufferCache.empty())
+ {
+ alDeleteBuffers(1, &mBufferCache.begin()->second);
+ mBufferCache.erase(mBufferCache.begin());
+ }
+
+ alcMakeContextCurrent(0);
+ if(mContext)
+ alcDestroyContext(mContext);
+ mContext = 0;
+ if(mDevice)
+ alcCloseDevice(mDevice);
+ mDevice = 0;
+}
+
+
+ALuint OpenAL_Output::getBuffer(const std::string &fname)
+{
+ ALuint buf = 0;
+
+ NameMap::iterator iditer = mBufferCache.find(fname);
+ if(iditer != mBufferCache.end())
+ {
+ buf = iditer->second;
+ if(mBufferRefs[buf]++ == 0)
+ {
+ IDDq::iterator iter = std::find(mUnusedBuffers.begin(),
+ mUnusedBuffers.end(), buf);
+ if(iter != mUnusedBuffers.end())
+ mUnusedBuffers.erase(iter);
+ }
+
+ return buf;
+ }
+ throwALerror();
+
+ std::vector data;
+ ChannelConfig chans;
+ SampleType type;
+ ALenum format;
+ int srate;
+
+ DecoderPtr decoder = mManager.getDecoder();
+ try
+ {
+ decoder->open(fname);
+ }
+ catch(Ogre::FileNotFoundException &e)
+ {
+ std::string::size_type pos = fname.rfind('.');
+ if(pos == std::string::npos)
+ throw;
+ decoder->open(fname.substr(0, pos)+".mp3");
+ }
+
+ decoder->getInfo(&srate, &chans, &type);
+ format = getALFormat(chans, type);
+
+ decoder->readAll(data);
+ decoder->close();
+
+ alGenBuffers(1, &buf);
+ throwALerror();
+
+ alBufferData(buf, format, data.data(), data.size(), srate);
+ mBufferCache[fname] = buf;
+ mBufferRefs[buf] = 1;
+
+ ALint bufsize = 0;
+ alGetBufferi(buf, AL_SIZE, &bufsize);
+ mBufferCacheMemSize += bufsize;
+
+ // NOTE: Max buffer cache: 15MB
+ while(mBufferCacheMemSize > 15*1024*1024)
+ {
+ if(mUnusedBuffers.empty())
+ {
+ std::cout <<"No more unused buffers to clear!"<< std::endl;
+ break;
+ }
+
+ ALuint oldbuf = mUnusedBuffers.front();
+ mUnusedBuffers.pop_front();
+
+ NameMap::iterator nameiter = mBufferCache.begin();
+ while(nameiter != mBufferCache.end())
+ {
+ if(nameiter->second == oldbuf)
+ mBufferCache.erase(nameiter++);
+ else
+ nameiter++;
+ }
+
+ bufsize = 0;
+ alGetBufferi(oldbuf, AL_SIZE, &bufsize);
+ alDeleteBuffers(1, &oldbuf);
+ mBufferCacheMemSize -= bufsize;
+ }
+ return buf;
+}
+
+void OpenAL_Output::bufferFinished(ALuint buf)
+{
+ if(mBufferRefs.at(buf)-- == 1)
+ {
+ mBufferRefs.erase(mBufferRefs.find(buf));
+ mUnusedBuffers.push_back(buf);
+ }
+}
+
+
+Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, bool loop)
+{
+ throwALerror();
+
+ std::auto_ptr sound;
+ ALuint src=0, buf=0;
+
+ if(mFreeSources.empty())
+ fail("No free sources");
+ src = mFreeSources.back();
+ mFreeSources.pop_back();
+
+ try
+ {
+ buf = getBuffer(fname);
+ sound.reset(new OpenAL_Sound(*this, src, buf));
+ }
+ catch(std::exception &e)
+ {
+ mFreeSources.push_back(src);
+ if(buf && alIsBuffer(buf))
+ bufferFinished(buf);
+ alGetError();
+ throw;
+ }
+
+ alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f);
+ alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
+ alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+
+ alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f);
+ alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
+ alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
+
+ alSourcef(src, AL_GAIN, volume);
+ alSourcef(src, AL_PITCH, pitch);
+
+ alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
+ alSourcei(src, AL_LOOPING, (loop?AL_TRUE:AL_FALSE));
+ throwALerror();
+
+ alSourcei(src, AL_BUFFER, buf);
+ alSourcePlay(src);
+ throwALerror();
+
+ return sound.release();
+}
+
+Sound* OpenAL_Output::playSound3D(const std::string &fname, const float *pos, float volume, float pitch,
+ float min, float max, bool loop)
+{
+ throwALerror();
+
+ std::auto_ptr sound;
+ ALuint src=0, buf=0;
+
+ if(mFreeSources.empty())
+ fail("No free sources");
+ src = mFreeSources.back();
+ mFreeSources.pop_back();
+
+ try
+ {
+ buf = getBuffer(fname);
+ sound.reset(new OpenAL_Sound(*this, src, buf));
+ }
+ catch(std::exception &e)
+ {
+ mFreeSources.push_back(src);
+ if(buf && alIsBuffer(buf))
+ bufferFinished(buf);
+ alGetError();
+ throw;
+ }
+
+ alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]);
+ alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
+ alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+
+ alSourcef(src, AL_REFERENCE_DISTANCE, min);
+ alSourcef(src, AL_MAX_DISTANCE, max);
+ alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f);
+
+ alSourcef(src, AL_GAIN, volume);
+ alSourcef(src, AL_PITCH, pitch);
+
+ alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE);
+ alSourcei(src, AL_LOOPING, (loop?AL_TRUE:AL_FALSE));
+ throwALerror();
+
+ alSourcei(src, AL_BUFFER, buf);
+ alSourcePlay(src);
+ throwALerror();
+
+ return sound.release();
+}
+
+
+Sound* OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch)
+{
+ throwALerror();
+
+ std::auto_ptr sound;
+ ALuint src;
+
+ if(mFreeSources.empty())
+ fail("No free sources");
+ src = mFreeSources.back();
+ mFreeSources.pop_back();
+
+ try
+ {
+ DecoderPtr decoder = mManager.getDecoder();
+ decoder->open(fname);
+ sound.reset(new OpenAL_SoundStream(*this, src, decoder));
+ }
+ catch(std::exception &e)
+ {
+ mFreeSources.push_back(src);
+ throw;
+ }
+
+ alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f);
+ alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
+ alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+
+ alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f);
+ alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
+ alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
+
+ alSourcef(src, AL_GAIN, volume);
+ alSourcef(src, AL_PITCH, pitch);
+
+ alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
+ alSourcei(src, AL_LOOPING, AL_FALSE);
+ throwALerror();
+
+ sound->play();
+ return sound.release();
+}
+
+Sound* OpenAL_Output::streamSound3D(const std::string &fname, const float *pos, float volume, float pitch,
+ float min, float max)
+{
+ throwALerror();
+
+ std::auto_ptr sound;
+ ALuint src;
+
+ if(mFreeSources.empty())
+ fail("No free sources");
+ src = mFreeSources.back();
+ mFreeSources.pop_back();
+
+ try
+ {
+ DecoderPtr decoder = mManager.getDecoder();
+ decoder->open(fname);
+ sound.reset(new OpenAL_SoundStream(*this, src, decoder));
+ }
+ catch(std::exception &e)
+ {
+ mFreeSources.push_back(src);
+ throw;
+ }
+
+ alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]);
+ alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
+ alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+
+ alSourcef(src, AL_REFERENCE_DISTANCE, min);
+ alSourcef(src, AL_MAX_DISTANCE, max);
+ alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f);
+
+ alSourcef(src, AL_GAIN, volume);
+ alSourcef(src, AL_PITCH, pitch);
+
+ alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE);
+ alSourcei(src, AL_LOOPING, AL_FALSE);
+ throwALerror();
+
+ sound->play();
+ return sound.release();
+}
+
+
+void OpenAL_Output::updateListener(const float *pos, const float *atdir, const float *updir)
+{
+ float orient[6] = {
+ atdir[0], atdir[2], -atdir[1],
+ updir[0], updir[2], -updir[1]
+ };
+
+ alListener3f(AL_POSITION, pos[0], pos[2], -pos[1]);
+ alListenerfv(AL_ORIENTATION, orient);
+ throwALerror();
+}
+
+
+OpenAL_Output::OpenAL_Output(SoundManager &mgr)
+ : Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0),
+ mStreamThread(new StreamThread)
+{
+}
+
+OpenAL_Output::~OpenAL_Output()
+{
+ deinit();
+}
+
+}
diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp
new file mode 100644
index 0000000000..e8154e9063
--- /dev/null
+++ b/apps/openmw/mwsound/openal_output.hpp
@@ -0,0 +1,73 @@
+#ifndef GAME_SOUND_OPENAL_OUTPUT_H
+#define GAME_SOUND_OPENAL_OUTPUT_H
+
+#include
+#include
+#include
+#include
+
+#include "alc.h"
+#include "al.h"
+
+#include "sound_output.hpp"
+
+namespace MWSound
+{
+ class SoundManager;
+ class Sound;
+
+ class OpenAL_Output : public Sound_Output
+ {
+ ALCdevice *mDevice;
+ ALCcontext *mContext;
+
+ typedef std::vector IDVec;
+ IDVec mFreeSources;
+
+ typedef std::map NameMap;
+ NameMap mBufferCache;
+
+ typedef std::map IDRefMap;
+ IDRefMap mBufferRefs;
+
+ typedef std::deque IDDq;
+ IDDq mUnusedBuffers;
+
+ uint64_t mBufferCacheMemSize;
+
+ ALuint getBuffer(const std::string &fname);
+ void bufferFinished(ALuint buffer);
+
+ virtual std::vector enumerate();
+ virtual void init(const std::string &devname="");
+ virtual void deinit();
+
+ virtual Sound *playSound(const std::string &fname, float volume, float pitch, bool loop);
+ virtual Sound *playSound3D(const std::string &fname, const float *pos, float volume, float pitch,
+ float min, float max, bool loop);
+
+ virtual Sound *streamSound(const std::string &fname, float volume, float pitch);
+ virtual Sound *streamSound3D(const std::string &fname, const float *pos, float volume, float pitch,
+ float min, float max);
+
+ virtual void updateListener(const float *pos, const float *atdir, const float *updir);
+
+ OpenAL_Output& operator=(const OpenAL_Output &rhs);
+ OpenAL_Output(const OpenAL_Output &rhs);
+
+ OpenAL_Output(SoundManager &mgr);
+ virtual ~OpenAL_Output();
+
+ class StreamThread;
+ std::auto_ptr mStreamThread;
+
+ friend class OpenAL_Sound;
+ friend class OpenAL_SoundStream;
+ friend class SoundManager;
+ };
+#ifndef DEFAULT_OUTPUT
+#define DEFAULT_OUTPUT (::MWSound::OpenAL_Output)
+#endif
+};
+
+#endif
diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp
new file mode 100644
index 0000000000..f9e7ab4278
--- /dev/null
+++ b/apps/openmw/mwsound/sound.hpp
@@ -0,0 +1,24 @@
+#ifndef GAME_SOUND_SOUND_H
+#define GAME_SOUND_SOUND_H
+
+namespace MWSound
+{
+ class Sound
+ {
+ virtual void stop() = 0;
+ virtual bool isPlaying() = 0;
+ virtual void update(const float *pos) = 0;
+
+ Sound& operator=(const Sound &rhs);
+ Sound(const Sound &rhs);
+
+ public:
+ Sound() { }
+ virtual ~Sound() { }
+
+ friend class OpenAL_Output;
+ friend class SoundManager;
+ };
+}
+
+#endif
diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp
new file mode 100644
index 0000000000..9c28d5ff55
--- /dev/null
+++ b/apps/openmw/mwsound/sound_decoder.hpp
@@ -0,0 +1,48 @@
+#ifndef GAME_SOUND_SOUND_DECODER_H
+#define GAME_SOUND_SOUND_DECODER_H
+
+#include
+
+#include
+
+namespace MWSound
+{
+ enum SampleType {
+ SampleType_UInt8,
+ SampleType_Int16
+ };
+ const char *getSampleTypeName(SampleType type);
+
+ enum ChannelConfig {
+ ChannelConfig_Mono,
+ ChannelConfig_Stereo
+ };
+ const char *getChannelConfigName(ChannelConfig config);
+
+ size_t framesToBytes(size_t frames, ChannelConfig config, SampleType type);
+ size_t bytesToFrames(size_t bytes, ChannelConfig config, SampleType type);
+
+ struct Sound_Decoder
+ {
+ Ogre::ResourceGroupManager &mResourceMgr;
+
+ virtual void open(const std::string &fname) = 0;
+ virtual void close() = 0;
+
+ virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0;
+
+ virtual size_t read(char *buffer, size_t bytes) = 0;
+ virtual void readAll(std::vector &output);
+ virtual void rewind() = 0;
+
+ Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton())
+ { }
+ virtual ~Sound_Decoder() { }
+
+ private:
+ Sound_Decoder(const Sound_Decoder &rhs);
+ Sound_Decoder& operator=(const Sound_Decoder &rhs);
+ };
+}
+
+#endif
diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp
new file mode 100644
index 0000000000..1722165e49
--- /dev/null
+++ b/apps/openmw/mwsound/sound_output.hpp
@@ -0,0 +1,44 @@
+#ifndef GAME_SOUND_SOUND_OUTPUT_H
+#define GAME_SOUND_SOUND_OUTPUT_H
+
+#include
+#include
+
+#include "../mwworld/ptr.hpp"
+
+namespace MWSound
+{
+ class SoundManager;
+ class Sound_Decoder;
+ class Sound;
+
+ class Sound_Output
+ {
+ SoundManager &mManager;
+
+ virtual std::vector enumerate() = 0;
+ virtual void init(const std::string &devname="") = 0;
+ virtual void deinit() = 0;
+
+ virtual Sound *playSound(const std::string &fname, float volume, float pitch, bool loop) = 0;
+ virtual Sound *playSound3D(const std::string &fname, const float *pos, float volume, float pitch,
+ float min, float max, bool loop) = 0;
+ virtual Sound *streamSound(const std::string &fname, float volume, float pitch) = 0;
+ virtual Sound *streamSound3D(const std::string &fname, const float *pos, float volume, float pitch,
+ float min, float max) = 0;
+
+ virtual void updateListener(const float *pos, const float *atdir, const float *updir) = 0;
+
+ Sound_Output& operator=(const Sound_Output &rhs);
+ Sound_Output(const Sound_Output &rhs);
+
+ Sound_Output(SoundManager &mgr) : mManager(mgr) { }
+ public:
+ virtual ~Sound_Output() { }
+
+ friend class OpenAL_Output;
+ friend class SoundManager;
+ };
+}
+
+#endif
diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp
index 226796603e..f626ec1584 100644
--- a/apps/openmw/mwsound/soundmanager.cpp
+++ b/apps/openmw/mwsound/soundmanager.cpp
@@ -6,111 +6,79 @@
#include
-#include
-#include
-#include
-
#include
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
#include "../mwworld/player.hpp"
-/* Set up the sound manager to use Audiere, FFMPEG or
- MPG123/libsndfile for input. The OPENMW_USE_x macros are set in
- CMakeLists.txt.
-*/
-#ifdef OPENMW_USE_AUDIERE
-#include
-#define SOUND_FACTORY OpenAL_Audiere_Factory
-#define SOUND_OUT "OpenAL"
-#define SOUND_IN "Audiere"
-#endif
+#include "sound_output.hpp"
+#include "sound_decoder.hpp"
+#include "sound.hpp"
-#ifdef OPENMW_USE_FFMPEG
-#include
-#define SOUND_FACTORY OpenAL_FFMpeg_Factory
+#include "openal_output.hpp"
#define SOUND_OUT "OpenAL"
+/* Set up the sound manager to use FFMPEG or MPG123+libsndfile for input. The
+ * OPENMW_USE_x macros are set in CMakeLists.txt.
+*/
+#ifdef OPENMW_USE_FFMPEG
+#include "ffmpeg_decoder.hpp"
+#ifndef SOUND_IN
#define SOUND_IN "FFmpeg"
#endif
+#endif
#ifdef OPENMW_USE_MPG123
-#include
-#define SOUND_FACTORY OpenAL_SndFile_Mpg123_Factory
-#define SOUND_OUT "OpenAL"
+#include "mpgsnd_decoder.hpp"
+#ifndef SOUND_IN
#define SOUND_IN "mpg123,sndfile"
#endif
+#endif
-using namespace Mangle::Sound;
-typedef OEngine::Sound::SoundManager OEManager;
-
-// Set the position on a sound based on a Ptr.
-static void setPos(SoundPtr &snd, const MWWorld::Ptr ref)
-{
- // Get sound position from the reference
- const float *pos = ref.getCellRef().pos.pos;
-
- // Move the sound, converting from MW coordinates to Ogre
- // coordinates.
- snd->setPos(pos[0], pos[2], -pos[1]);
-}
namespace MWSound
{
-
- SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera,
- const Files::PathContainer& dataDirs,
- bool useSound, bool fsstrict, MWWorld::Environment& environment)
- : mFSStrict(fsstrict)
+ SoundManager::SoundManager(bool useSound, MWWorld::Environment& environment)
+ : mResourceMgr(Ogre::ResourceGroupManager::getSingleton())
, mEnvironment(environment)
- , mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY)))
- , updater(mgr)
- , cameraTracker(mgr)
- , mCurrentPlaylist(NULL)
- , mUsingSound(useSound)
{
- if(useSound)
+ if(!useSound)
+ return;
+
+ std::cout << "Sound output: " << SOUND_OUT << std::endl;
+ std::cout << "Sound decoder: " << SOUND_IN << std::endl;
+
+ try
{
- // The music library will accept these filetypes
- // If none is given then it will accept all filetypes
- std::vector acceptableExtensions;
- acceptableExtensions.push_back(".mp3");
- acceptableExtensions.push_back(".wav");
- acceptableExtensions.push_back(".ogg");
- acceptableExtensions.push_back(".flac");
+ mOutput.reset(new DEFAULT_OUTPUT(*this));
- // 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);
- }
+ std::vector names = mOutput->enumerate();
+ std::cout <<"Enumerated output devices:"<< std::endl;
+ for(size_t i = 0;i < names.size();i++)
+ std::cout <<" "<addFrameListener(&updater);
+ mOutput->init();
}
- }
+ catch(std::exception &e)
+ {
+ std::cout <<"Sound init failed: "<getStore().sounds.search(soundId);
- if(snd == NULL) return "";
+ const ESM::Sound *snd = mEnvironment.mWorld->getStore().sounds.search(soundId);
+ if(snd == NULL)
+ throw std::runtime_error(std::string("Failed to lookup sound ")+soundId);
- if(snd->data.volume == 0)
- volume = 0.0f;
- else
- volume *= pow(10.0, (snd->data.volume/255.0f*3348.0 - 3348.0) / 2000.0);
+ if(snd->data.volume == 0)
+ volume = 0.0f;
+ else
+ volume *= pow(10.0, (snd->data.volume/255.0f*3348.0 - 3348.0) / 2000.0);
- if(snd->data.minRange == 0 && snd->data.maxRange == 0)
- {
- min = 100.0f;
- max = 2000.0f;
- }
- else
- {
- min = snd->data.minRange * 20.0f;
- max = snd->data.maxRange * 50.0f;
- min = std::max(min, 1.0f);
- max = std::max(min, max);
- }
-
- return Files::FileListLocator(mSoundFiles, snd->sound, mFSStrict, false);
- }
-
- // Add a sound to the list and play it
- void SoundManager::add(const std::string &file,
- MWWorld::Ptr ptr,
- const std::string &id,
- float volume, float pitch,
- float min, float max,
- bool loop, bool untracked)
- {
- try
+ if(snd->data.minRange == 0 && snd->data.maxRange == 0)
{
- SoundPtr snd = mgr->load(file);
- snd->setRepeat(loop);
- snd->setVolume(volume);
- snd->setPitch(pitch);
- snd->setRange(min,max);
- setPos(snd, ptr);
- snd->play();
-
- if (!untracked)
- {
- sounds[ptr][id] = WSoundPtr(snd);
- }
- }
- catch(...)
- {
- std::cout << "Error loading " << file << ", skipping.\n";
- }
- }
-
- // Clears all the sub-elements of a given iterator, and then
- // removes it from 'sounds'.
- void SoundManager::clearAll(PtrMap::iterator& it)
- {
- IDMap::iterator sit = it->second.begin();
-
- while(sit != it->second.end())
- {
- // Get sound pointer, if any
- SoundPtr snd = sit->second.lock();
-
- // Stop the sound
- if(snd) snd->stop();
-
- sit++;
- }
-
- // Remove the ptr reference
- sounds.erase(it);
- }
-
- // Stop a sound and remove it from the list. If id="" then
- // remove the entire object and stop all its sounds.
- void SoundManager::remove(MWWorld::Ptr ptr, const std::string &id)
- {
- PtrMap::iterator it = sounds.find(ptr);
- if(it != sounds.end())
- {
- if(id == "")
- // Kill all references to 'ptr'
- clearAll(it);
- else
- {
- // Only find the id we're looking for
- IDMap::iterator it2 = it->second.find(id);
- if(it2 != it->second.end())
- {
- // Stop the sound and remove it from the list
- SoundPtr snd = it2->second.lock();
- if(snd) snd->stop();
- it->second.erase(it2);
- }
- }
- }
- }
-
- bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const
- {
- PtrMap::const_iterator it = sounds.find(ptr);
- if(it != sounds.end())
- {
- IDMap::const_iterator it2 = it->second.find(id);
- if(it2 != it->second.end())
- {
- // Get a shared_ptr from the weak_ptr
- SoundPtr snd = it2->second.lock();;
-
- // Is it still alive?
- if(snd)
- {
- // Then return its status!
- return snd->isPlaying();
- }
- }
- }
- // Nothing found, sound is not playing
- return false;
- }
-
- // Remove all references to objects belonging to a given cell
- void SoundManager::removeCell(const MWWorld::Ptr::CellStore *cell)
- {
- PtrMap::iterator it2, it = sounds.begin();
- while(it != sounds.end())
- {
- // Make sure to increase the iterator before we erase it.
- it2 = it++;
- if(it2->first.getCell() == cell)
- clearAll(it2);
- }
- }
-
- void SoundManager::updatePositions(MWWorld::Ptr ptr)
- {
- // Find the reference (if any)
- PtrMap::iterator it = sounds.find(ptr);
- if(it != sounds.end())
- {
- // Then find all sounds in it (if any)
- IDMap::iterator it2 = it->second.begin();
- for(;it2 != it->second.end(); it2++)
- {
- // Get the sound (if it still exists)
- SoundPtr snd = it2->second.lock();
- if(snd)
- // Update position
- setPos(snd, ptr);
- }
- }
- }
-
- void SoundManager::stopMusic()
- {
- if (music)
- music->stop();
- setPlaylist();
- }
-
-
- void SoundManager::streamMusicFull(const std::string& filename)
- {
- // Play the sound and tell it to stream, if possible. TODO:
- // Store the reference, the jukebox will need to check status,
- // control volume etc.
- if (music)
- music->stop();
- music = mgr->load(filename);
- music->setStreaming(true);
- music->setVolume(0.4);
- music->play();
-
- }
-
- void SoundManager::streamMusic(const std::string& filename)
- {
- std::string filePath = mMusicLibrary.locate(filename, mFSStrict, true).string();
- if(!filePath.empty())
- {
- streamMusicFull(filePath);
- }
- }
-
- void SoundManager::startRandomTitle()
- {
- if(mCurrentPlaylist && !mCurrentPlaylist->empty())
- {
- Files::PathContainer::const_iterator fileIter = mCurrentPlaylist->begin();
- srand( time(NULL) );
- int r = rand() % mCurrentPlaylist->size() + 1; //old random code
-
- std::advance(fileIter, r - 1);
- std::string music = fileIter->string();
- std::cout << "Playing " << music << "\n";
-
- try
- {
- streamMusicFull(music);
- }
- catch (std::exception &e)
- {
- std::cout << " Music Error: " << e.what() << "\n";
- }
- }
- }
-
- bool SoundManager::isMusicPlaying()
- {
- bool test = false;
- if(music)
- {
- test = music->isPlaying();
- }
- return test;
- }
-
- bool SoundManager::setPlaylist(std::string playlist)
- {
- const Files::PathContainer* previousPlaylist;
- previousPlaylist = mCurrentPlaylist;
- if (playlist == "")
- {
- mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict);
- }
- else if(mMusicLibrary.containsSection(playlist, mFSStrict))
- {
- mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict);
+ min = 100.0f;
+ max = 2000.0f;
}
else
{
- std::cout << "Warning: playlist named " << playlist << " does not exist.\n";
+ min = snd->data.minRange * 20.0f;
+ max = snd->data.maxRange * 50.0f;
+ min = std::max(min, 1.0f);
+ max = std::max(min, max);
}
- return previousPlaylist == mCurrentPlaylist;
+
+ return std::string("Sound/")+snd->sound;
}
- void SoundManager::playPlaylist(std::string playlist)
+
+ bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const
{
- if (!mUsingSound)
+ SoundMap::const_iterator snditer = mActiveSounds.find(ptr);
+ if(snditer == mActiveSounds.end())
+ return false;
+
+ IDMap::const_iterator iditer = snditer->second.find(id);
+ if(iditer == snditer->second.end())
+ return false;
+
+ return true;
+ }
+
+
+ void SoundManager::stopMusic()
+ {
+ if(mMusic)
+ mMusic->stop();
+ mMusic.reset();
+ }
+
+ void SoundManager::streamMusicFull(const std::string& filename)
+ {
+ std::cout <<"Playing "<stop();
+ mMusic.reset(mOutput->streamSound(filename, 0.4f, 1.0f));
+ }
+ catch(std::exception &e)
+ {
+ std::cout << "Music Error: " << e.what() << "\n";
+ }
+ }
+
+ void SoundManager::streamMusic(const std::string& filename)
+ {
+ streamMusicFull("Music/"+filename);
+ }
+
+ void SoundManager::startRandomTitle()
+ {
+ Ogre::StringVectorPtr filelist;
+ filelist = mResourceMgr.findResourceNames(Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
+ "Music/"+mCurrentPlaylist+"/*");
+ if(!filelist->size())
return;
- if (playlist == "")
- {
- if(!isMusicPlaying())
- {
- startRandomTitle();
- }
- return;
- }
-
- if(!setPlaylist(playlist))
- {
- startRandomTitle();
- }
- else if (!isMusicPlaying())
- {
- startRandomTitle();
- }
+ int i = rand()%filelist->size();
+ streamMusicFull((*filelist)[i]);
}
- void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename)
- {
- if (!mUsingSound)
- return;
-
- // The range values are not tested
- std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict, true);
- if(!filePath.empty())
- add(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false);
- else
- std::cout << "Sound file " << filename << " not found, skipping.\n";
- }
-
- bool SoundManager::sayDone (MWWorld::Ptr ptr) const
- {
- return !isPlaying(ptr, "_say_sound");
- }
-
-
- void SoundManager::playSound(const std::string& soundId, float volume, float pitch, bool loop)
- {
- float min, max;
- const std::string &file = lookup(soundId, volume, min, max);
- if (file != "")
+ bool SoundManager::isMusicPlaying()
{
- SoundPtr snd = mgr->load(file);
- snd->setRepeat(loop);
- snd->setVolume(volume);
- snd->setRange(min,max);
- snd->setPitch(pitch);
- snd->setRelative(true);
- snd->play();
+ return mMusic && mMusic->isPlaying();
+ }
- if (loop)
+ void SoundManager::playPlaylist(const std::string &playlist)
+ {
+ mCurrentPlaylist = playlist;
+ startRandomTitle();
+ }
+
+ void SoundManager::say(MWWorld::Ptr ptr, const std::string& filename)
+ {
+ try
{
- // Only add the looping sound once
- IDMap::iterator it = mLoopedSounds.find(soundId);
- if(it == mLoopedSounds.end())
- {
- mLoopedSounds[soundId] = WSoundPtr(snd);
- }
+ // The range values are not tested
+ const ESM::Position &pos = ptr.getCellRef().pos;
+ std::string filePath = std::string("Sound/")+filename;
+
+ SoundPtr sound(mOutput->playSound3D(filePath, pos.pos, 1.0f, 1.0f, 100.0f, 20000.0f, false));
+ mActiveSounds[ptr]["_say_sound"] = sound;
+ }
+ catch(std::exception &e)
+ {
+ std::cout <<"Sound Error: "<playSound(file, volume, pitch, loop);
+ mLooseSounds[soundId] = SoundPtr(sound);
+ }
+ catch(std::exception &e)
+ {
+ std::cout <<"Sound Error: "<playSound3D(file, pos.pos, volume, pitch, min, max, loop));
+ if(untracked) mLooseSounds[soundId] = sound;
+ else mActiveSounds[ptr][soundId] = sound;
+ }
+ catch(std::exception &e)
+ {
+ std::cout <<"Sound Error: "<second.find(soundId);
+ if(iditer != snditer->second.end())
+ {
+ iditer->second->stop();
+ snditer->second.erase(iditer);
+ if(snditer->second.empty())
+ mActiveSounds.erase(snditer);
+ }
+ }
+ else
+ {
+ IDMap::iterator iditer = snditer->second.begin();
+ while(iditer != snditer->second.end())
+ {
+ iditer->second->stop();
+ iditer++;
+ }
+ mActiveSounds.erase(snditer);
+ }
+ }
+
+ void SoundManager::stopSound(MWWorld::Ptr::CellStore *cell)
+ {
+ // Remove all references to objects belonging to a given cell
+ SoundMap::iterator snditer = mActiveSounds.begin();
+ while(snditer != mActiveSounds.end())
+ {
+ if(snditer->first.getCell() == cell)
+ {
+ IDMap::iterator iditer = snditer->second.begin();
+ while(iditer != snditer->second.end())
+ {
+ iditer->second->stop();
+ iditer++;
+ }
+ mActiveSounds.erase(snditer++);
+ }
+ else
+ snditer++;
+ }
+ }
void SoundManager::stopSound(const std::string& soundId)
{
- IDMap::iterator it = mLoopedSounds.find(soundId);
- if(it != mLoopedSounds.end())
+ IDMap::iterator iditer = mLooseSounds.find(soundId);
+ if(iditer != mLooseSounds.end())
{
- SoundPtr snd = it->second.lock();
- if(snd) snd->stop();
- mLoopedSounds.erase(it);
+ iditer->second->stop();
+ mLooseSounds.erase(iditer);
}
}
- bool SoundManager::getSoundPlaying (MWWorld::Ptr ptr, const std::string& soundId) const
- {
- // Mark all sounds as playing, otherwise the scripts will just
- // keep trying to play them every frame.
+ bool SoundManager::getSoundPlaying(MWWorld::Ptr ptr, const std::string& soundId) const
+ {
+ return isPlaying(ptr, soundId);
+ }
- return isPlaying(ptr, soundId);
- }
+ void SoundManager::updateObject(MWWorld::Ptr ptr)
+ {
+ SoundMap::iterator snditer = mActiveSounds.find(ptr);
+ if(snditer == mActiveSounds.end())
+ return;
- void SoundManager::updateObject(MWWorld::Ptr ptr)
- {
- updatePositions(ptr);
- }
+ const ESM::Position &pos = ptr.getCellRef().pos;
+ IDMap::iterator iditer = snditer->second.begin();
+ while(iditer != snditer->second.end())
+ {
+ iditer->second->update(pos.pos);
+ iditer++;
+ }
+ }
- void SoundManager::update (float duration)
- {
+ void SoundManager::updateRegionSound(float duration)
+ {
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(!(current->cell->data.flags & current->cell->Interior) && timePassed >= 10)
+ timePassed += duration;
+ if((current->cell->data.flags & current->cell->Interior) || timePassed < 10)
+ return;
+ timePassed = 0;
+
+ if(regionName != 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;
- }
-
- if(test.soundList.size() > 0)
- {
- std::vector::iterator soundIter = test.soundList.begin();
- //mEnvironment.mSoundManager
- if(total == 0)
- {
- while (soundIter != test.soundList.end())
- {
- int chance = (int) soundIter->chance;
- //ESM::NAME32 go = soundIter->sound;
- //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
- soundIter++;
- total += chance;
- }
- }
-
- int r = rand() % total; //old random code
- int pos = 0;
- soundIter = test.soundList.begin();
- while (soundIter != test.soundList.end())
- {
- const std::string go = soundIter->sound.toString();
- int chance = (int) soundIter->chance;
- //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
- soundIter++;
- if( r - pos < chance)
- {
- //play sound
- std::cout << "Sound: " << go <<" Chance:" << chance << "\n";
- mEnvironment.mSoundManager->playSound(go, 20.0, 1.0);
-
- break;
- }
- pos += chance;
- }
- }
- }
- else if(current->cell->data.flags & current->cell->Interior)
- {
- regionName = "";
+ regionName = current->cell->region;
+ total = 0;
}
- }
+ const ESM::Region *regn = mEnvironment.mWorld->getStore().regions.find(regionName);
+ std::vector::const_iterator soundIter;
+ if(total == 0)
+ {
+ soundIter = regn->soundList.begin();
+ while(soundIter != regn->soundList.end())
+ {
+ total += (int)soundIter->chance;
+ soundIter++;
+ }
+ if(total == 0)
+ return;
+ }
+
+ int r = (int)(rand()/((double)RAND_MAX+1) * total);
+ int pos = 0;
+
+ soundIter = regn->soundList.begin();
+ while(soundIter != regn->soundList.end())
+ {
+ const std::string go = soundIter->sound.toString();
+ int chance = (int) soundIter->chance;
+ //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
+ soundIter++;
+ if(r - pos < chance)
+ {
+ //play sound
+ std::cout << "Sound: " << go <<" Chance:" << chance << "\n";
+ playSound(go, 1.0f, 1.0f);
+ break;
+ }
+ pos += chance;
+ }
+ }
+
+ void SoundManager::updateSounds(float duration)
+ {
+ static float timePassed = 0.0;
+
+ timePassed += duration;
+ if(timePassed < (1.0f/30.0f))
+ return;
+ timePassed = 0.0f;
+
+ // Make sure music is still playing
+ if(!isMusicPlaying())
+ startRandomTitle();
+
+ Ogre::Camera *cam = mEnvironment.mWorld->getPlayer().getRenderer()->getCamera();
+ Ogre::Vector3 nPos, nDir, nUp;
+ nPos = cam->getRealPosition();
+ nDir = cam->getRealDirection();
+ nUp = cam->getRealUp();
+
+ // The output handler is expecting vectors oriented like the game
+ // (that is, -Z goes down, +Y goes forward), but that's not what we
+ // get from Ogre's camera, so we have to convert.
+ float pos[3] = { nPos[0], -nPos[2], nPos[1] };
+ float at[3] = { nDir[0], -nDir[2], nDir[1] };
+ float up[3] = { nUp[0], -nUp[2], nUp[1] };
+ mOutput->updateListener(pos, at, up);
+
+ // Check if any sounds are finished playing, and trash them
+ SoundMap::iterator snditer = mActiveSounds.begin();
+ while(snditer != mActiveSounds.end())
+ {
+ IDMap::iterator iditer = snditer->second.begin();
+ while(iditer != snditer->second.end())
+ {
+ if(!iditer->second->isPlaying())
+ snditer->second.erase(iditer++);
+ else
+ iditer++;
+ }
+ if(snditer->second.empty())
+ mActiveSounds.erase(snditer++);
+ else
+ snditer++;
+ }
+
+ IDMap::iterator iditer = mLooseSounds.begin();
+ while(iditer != mLooseSounds.end())
+ {
+ if(!iditer->second->isPlaying())
+ mLooseSounds.erase(iditer++);
+ else
+ iditer++;
+ }
+ }
+
+ void SoundManager::update(float duration)
+ {
+ updateSounds(duration);
+ updateRegionSound(duration);
+ }
+
+
+ // Default readAll implementation, for decoders that can't do anything
+ // better
+ void Sound_Decoder::readAll(std::vector &output)
+ {
+ size_t total = output.size();
+ size_t got;
+
+ output.resize(total+32768);
+ while((got=read(&output[total], output.size()-total)) > 0)
+ {
+ total += got;
+ output.resize(total*2);
+ }
+ output.resize(total);
+ }
+
+
+ const char *getSampleTypeName(SampleType type)
+ {
+ switch(type)
+ {
+ case SampleType_UInt8: return "U8";
+ case SampleType_Int16: return "S16";
+ }
+ return "(unknown sample type)";
+ }
+
+ const char *getChannelConfigName(ChannelConfig config)
+ {
+ switch(config)
+ {
+ case ChannelConfig_Mono: return "Mono";
+ case ChannelConfig_Stereo: return "Stereo";
+ }
+ return "(unknown channel config)";
+ }
+
+ size_t framesToBytes(size_t frames, ChannelConfig config, SampleType type)
+ {
+ switch(config)
+ {
+ case ChannelConfig_Mono: frames *= 1; break;
+ case ChannelConfig_Stereo: frames *= 2; break;
+ }
+ switch(type)
+ {
+ case SampleType_UInt8: frames *= 1; break;
+ case SampleType_Int16: frames *= 2; break;
+ }
+ return frames;
+ }
+
+ size_t bytesToFrames(size_t bytes, ChannelConfig config, SampleType type)
+ {
+ return bytes / framesToBytes(1, config, type);
+ }
}
diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp
index dcf64b90ca..a076c1cc01 100644
--- a/apps/openmw/mwsound/soundmanager.hpp
+++ b/apps/openmw/mwsound/soundmanager.hpp
@@ -3,10 +3,7 @@
#include
-#include
-#include
-
-#include
+#include
#include
@@ -19,16 +16,6 @@ namespace Ogre
class Camera;
}
-namespace Mangle
-{
- namespace Sound
- {
- typedef boost::shared_ptr SoundPtr;
- }
-}
-
-typedef OEngine::Sound::SoundManagerPtr OEManagerPtr;
-
namespace MWWorld
{
struct Environment;
@@ -36,128 +23,96 @@ namespace MWWorld
namespace MWSound
{
+ class Sound_Output;
+ struct Sound_Decoder;
+ class Sound;
+
+ typedef boost::shared_ptr DecoderPtr;
+
class SoundManager
{
+ Ogre::ResourceGroupManager& mResourceMgr;
- // 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 mFSStrict;
+ MWWorld::Environment& mEnvironment;
- MWWorld::Environment& mEnvironment;
+ std::auto_ptr mOutput;
- void streamMusicFull (const std::string& filename);
- ///< Play a soundifle
- /// \param absolute filename
+ boost::shared_ptr mMusic;
+ std::string mCurrentPlaylist;
- /* 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;
+ typedef boost::shared_ptr SoundPtr;
+ typedef std::map IDMap;
+ typedef std::map SoundMap;
+ SoundMap mActiveSounds;
+ IDMap mLooseSounds;
- /* This class calls update() on the sound manager each frame
- using and Ogre::FrameListener
- */
- Mangle::Sound::OgreOutputUpdater updater;
+ std::string lookup(const std::string &soundId,
+ float &volume, float &min, float &max);
+ void streamMusicFull(const std::string& filename);
+ bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const;
+ void updateSounds(float duration);
+ void updateRegionSound(float duration);
- /* This class tracks the movement of an Ogre::Camera and moves
- a sound listener automatically to follow it.
- */
- Mangle::Sound::OgreListenerMover cameraTracker;
+ SoundManager(const SoundManager &rhs);
+ SoundManager& operator=(const SoundManager &rhs);
- typedef std::map IDMap;
- typedef std::map PtrMap;
- PtrMap sounds;
+ protected:
+ DecoderPtr getDecoder();
+ friend class OpenAL_Output;
- // A list of all sound files used to lookup paths
- Files::PathContainer mSoundFiles;
+ public:
+ SoundManager(bool useSound, MWWorld::Environment& environment);
+ ~SoundManager();
- // A library of all Music file paths stored by the folder they are contained in
- Files::FileLibrary mMusicLibrary;
+ void stopMusic();
+ ///< Stops music if it's playing
- // Points to the current playlist of music files stored in the music library
- const Files::PathContainer* mCurrentPlaylist;
+ void streamMusic(const std::string& filename);
+ ///< Play a soundifle
+ /// \param filename name of a sound file in "Music/" in the data directory.
- IDMap mLoopedSounds;
+ void startRandomTitle();
+ ///< Starts a random track from the current playlist
- bool mUsingSound;
+ bool isMusicPlaying();
+ ///< Returns true if music is playing
- 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);
+ void playPlaylist(const std::string &playlist);
+ ///< Start playing music from the selected folder
+ /// \param name of the folder that contains the playlist
- public:
+ void say(MWWorld::Ptr reference, const std::string& filename);
+ ///< Make an actor say some text.
+ /// \param filename name of a sound file in "Sound/Vo/" in the data directory.
- SoundManager(Ogre::Root*, Ogre::Camera*,
- const Files::PathContainer& dataDir, bool useSound, bool fsstrict,
- MWWorld::Environment& environment);
- ~SoundManager();
+ bool sayDone(MWWorld::Ptr reference) const;
+ ///< Is actor not speaking?
- void stopMusic();
- ///< Stops music if it's playing
+ void playSound(const std::string& soundId, float volume, float pitch, bool loop=false);
+ ///< Play a sound, independently of 3D-position
- void streamMusic(const std::string& filename);
- ///< Play a soundifle
- /// \param filename name of a sound file in "Music/" in the data directory.
+ void playSound3D(MWWorld::Ptr reference, const std::string& soundId,
+ float volume, float pitch, bool loop,
+ bool untracked=false);
+ ///< Play a sound from an object
- void startRandomTitle();
- ///< Starts a random track from the current playlist
+ void stopSound3D(MWWorld::Ptr reference, const std::string& soundId="");
+ ///< Stop the given object from playing the given sound, If no soundId is given,
+ /// all sounds for this reference will stop.
- bool isMusicPlaying();
- ///< Returns true if music is playing
+ void stopSound(MWWorld::Ptr::CellStore *cell);
+ ///< Stop all sounds for the given cell.
- 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 stopSound(const std::string& soundId);
+ ///< Stop a non-3d looping sound
- 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
+ bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const;
+ ///< Is the given sound currently playing on the given object?
- void say (MWWorld::Ptr reference, const std::string& filename);
- ///< Make an actor say some text.
- /// \param filename name of a sound file in "Sound/Vo/" in the data directory.
+ void updateObject(MWWorld::Ptr reference);
+ ///< Update the position of all sounds connected to the given object.
- bool sayDone (MWWorld::Ptr reference) const;
- ///< Is actor not speaking?
-
- void playSound (const std::string& soundId, float volume, float pitch, bool loop=false);
- ///< Play a sound, independently of 3D-position
-
- void playSound3D (MWWorld::Ptr reference, const std::string& soundId,
- float volume, float pitch, bool loop, bool untracked=false);
- ///< Play a sound from an object
-
- void stopSound3D (MWWorld::Ptr reference, const std::string& soundId = "");
- ///< Stop the given object from playing the given sound, If no soundId is given,
- /// all sounds for this reference will stop.
-
- void stopSound (MWWorld::Ptr::CellStore *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;
- ///< Is the given sound currently playing on the given object?
-
- void updateObject(MWWorld::Ptr reference);
- ///< Update the position of all sounds connected to the given object.
-
- void update (float duration);
+ void update(float duration);
};
}
diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp
index c498cabced..2800b6f3c1 100644
--- a/apps/openmw/mwworld/containerstore.cpp
+++ b/apps/openmw/mwworld/containerstore.cpp
@@ -8,6 +8,29 @@
#include
#include "manualref.hpp"
+#include "refdata.hpp"
+
+namespace
+{
+ template
+ float getTotalWeight (const ESMS::CellRefList& cellRefList)
+ {
+ float sum = 0;
+
+ for (typename ESMS::CellRefList::List::const_iterator iter (
+ cellRefList.list.begin());
+ iter!=cellRefList.list.end();
+ ++iter)
+ {
+ if (iter->mData.getCount()>0)
+ sum += iter->mData.getCount()*iter->base->data.weight;
+ }
+
+ return sum;
+ }
+}
+
+MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {}
MWWorld::ContainerStore::~ContainerStore() {}
@@ -40,6 +63,8 @@ void MWWorld::ContainerStore::add (const Ptr& ptr)
case Type_Repair: repairs.list.push_back (*ptr.get()); break;
case Type_Weapon: weapons.list.push_back (*ptr.get()); break;
}
+
+ flagAsModified();
}
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS::ESMStore& store)
@@ -58,6 +83,8 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS:
ref.getPtr().getRefData().setCount (iter->count);
add (ref.getPtr());
}
+
+ flagAsModified();
}
void MWWorld::ContainerStore::clear()
@@ -74,6 +101,44 @@ void MWWorld::ContainerStore::clear()
probes.list.clear();
repairs.list.clear();
weapons.list.clear();
+
+ flagAsModified();
+}
+
+void MWWorld::ContainerStore::flagAsModified()
+{
+ ++mStateId;
+ mWeightUpToDate = false;
+}
+
+int MWWorld::ContainerStore::getStateId() const
+{
+ return mStateId;
+}
+
+float MWWorld::ContainerStore::getWeight() const
+{
+ if (!mWeightUpToDate)
+ {
+ mCachedWeight = 0;
+
+ mCachedWeight += getTotalWeight (potions);
+ mCachedWeight += getTotalWeight (appas);
+ mCachedWeight += getTotalWeight (armors);
+ mCachedWeight += getTotalWeight (books);
+ mCachedWeight += getTotalWeight (clothes);
+ mCachedWeight += getTotalWeight (ingreds);
+ mCachedWeight += getTotalWeight (lights);
+ mCachedWeight += getTotalWeight (lockpicks);
+ mCachedWeight += getTotalWeight (miscItems);
+ mCachedWeight += getTotalWeight (probes);
+ mCachedWeight += getTotalWeight (repairs);
+ mCachedWeight += getTotalWeight (weapons);
+
+ mWeightUpToDate = true;
+ }
+
+ return mCachedWeight;
}
int MWWorld::ContainerStore::getType (const Ptr& ptr)
@@ -301,23 +366,30 @@ MWWorld::Ptr *MWWorld::ContainerStoreIterator::operator->() const
MWWorld::Ptr MWWorld::ContainerStoreIterator::operator*() const
{
+ Ptr ptr;
+
switch (mType)
{
- case ContainerStore::Type_Potion: return MWWorld::Ptr (&*mPotion, 0);
- case ContainerStore::Type_Apparatus: return MWWorld::Ptr (&*mApparatus, 0);
- case ContainerStore::Type_Armor: return MWWorld::Ptr (&*mArmor, 0);
- case ContainerStore::Type_Book: return MWWorld::Ptr (&*mBook, 0);
- case ContainerStore::Type_Clothing: return MWWorld::Ptr (&*mClothing, 0);
- case ContainerStore::Type_Ingredient: return MWWorld::Ptr (&*mIngredient, 0);
- case ContainerStore::Type_Light: return MWWorld::Ptr (&*mLight, 0);
- case ContainerStore::Type_Lockpick: return MWWorld::Ptr (&*mLockpick, 0);
- case ContainerStore::Type_Miscellaneous: return MWWorld::Ptr (&*mMiscellaneous, 0);
- case ContainerStore::Type_Probe: return MWWorld::Ptr (&*mProbe, 0);
- case ContainerStore::Type_Repair: return MWWorld::Ptr (&*mRepair, 0);
- case ContainerStore::Type_Weapon: return MWWorld::Ptr (&*mWeapon, 0);
+ case ContainerStore::Type_Potion: ptr = MWWorld::Ptr (&*mPotion, 0); break;
+ case ContainerStore::Type_Apparatus: ptr = MWWorld::Ptr (&*mApparatus, 0); break;
+ case ContainerStore::Type_Armor: ptr = MWWorld::Ptr (&*mArmor, 0); break;
+ case ContainerStore::Type_Book: ptr = MWWorld::Ptr (&*mBook, 0); break;
+ case ContainerStore::Type_Clothing: ptr = MWWorld::Ptr (&*mClothing, 0); break;
+ case ContainerStore::Type_Ingredient: ptr = MWWorld::Ptr (&*mIngredient, 0); break;
+ case ContainerStore::Type_Light: ptr = MWWorld::Ptr (&*mLight, 0); break;
+ case ContainerStore::Type_Lockpick: ptr = MWWorld::Ptr (&*mLockpick, 0); break;
+ case ContainerStore::Type_Miscellaneous: ptr = MWWorld::Ptr (&*mMiscellaneous, 0); break;
+ case ContainerStore::Type_Probe: ptr = MWWorld::Ptr (&*mProbe, 0); break;
+ case ContainerStore::Type_Repair: ptr = MWWorld::Ptr (&*mRepair, 0); break;
+ case ContainerStore::Type_Weapon: ptr = MWWorld::Ptr (&*mWeapon, 0); break;
}
- throw std::runtime_error ("invalid pointer");
+ if (ptr.isEmpty())
+ throw std::runtime_error ("invalid iterator");
+
+ ptr.setContainerStore (mContainer);
+
+ return ptr;
}
MWWorld::ContainerStoreIterator& MWWorld::ContainerStoreIterator::operator++()
diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp
index 69e5ba4466..da5424fe08 100644
--- a/apps/openmw/mwworld/containerstore.hpp
+++ b/apps/openmw/mwworld/containerstore.hpp
@@ -52,9 +52,14 @@ namespace MWWorld
ESMS::CellRefList