Merge branch 'master' into physicsaedra2

Conflicts:
	apps/openmw/mwinput/inputmanager.cpp
	libs/openengine/bullet/physic.cpp
actorid
scrawl 13 years ago
commit 9e1a9e5758

@ -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.

@ -4,9 +4,6 @@ if (APPLE)
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
# using 10.6 sdk
set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.6.sdk")
endif (APPLE)
# Macros
@ -27,11 +24,12 @@ set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VE
configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp")
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
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_AUDIERE "use audiere for sound" OFF)
option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems")
@ -124,54 +122,41 @@ set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/trace.cpp
)
# 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)
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)
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)
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_AUDIERE)
find_package(Audiere REQUIRED)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR})
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE)
endif (USE_AUDIERE)
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)
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)
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})
source_group(libs\\openengine FILES ${OENGINE_ALL})
set(OPENMW_LIBS ${MANGLE_ALL} ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER)
# Platform specific
if (WIN32)
set(Boost_USE_STATIC_LIBS ON)
set(PLATFORM_INCLUDE_DIR "platform")
add_definitions(-DBOOST_ALL_NO_LIB)
else (WIN32)
@ -181,7 +166,6 @@ include_directories(${UUID_INCLUDE_DIR})
endif (WIN32)
if (MSVC10)
set(PLATFORM_INCLUDE_DIR "")
add_definitions(-DMYGUI_DONT_REPLACE_NULLPTR)
endif()
if (APPLE)
@ -190,7 +174,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)
@ -205,16 +195,17 @@ ENDIF(WIN32)
ENDIF(OGRE_STATIC)
include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS}
${OGRE_Terrain_INCLUDE_DIR}
${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
@ -224,14 +215,8 @@ 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/)
add_subdirectory( files/mygui )
# Specify build paths
@ -243,6 +228,9 @@ endif (APPLE)
# Other files
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}/settings-default.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
@ -269,8 +257,14 @@ if (APPLE)
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
# prepare plugins
if (${CMAKE_BUILD_TYPE} MATCHES "Release" OR
${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo")
if (${CMAKE_BUILD_TYPE} MATCHES "Release")
set(OPENMW_RELEASE_BUILD 1)
endif()
if (${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo")
set(OPENMW_RELEASE_BUILD 1)
endif()
if (${OPENMW_RELEASE_BUILD})
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
else()
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
@ -286,7 +280,16 @@ endif (APPLE)
# Compiler settings
if (CMAKE_COMPILER_IS_GNUCC)
add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-unused-but-set-parameter -Wno-reorder)
add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder)
# Silence warnings in OGRE headers. Remove once OGRE got fixed!
add_definitions (-Wno-ignored-qualifiers)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
add_definitions (-Wno-unused-but-set-parameter)
endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
endif (CMAKE_COMPILER_IS_GNUCC)
if(DPKG_PROGRAM)
@ -308,6 +311,7 @@ if(DPKG_PROGRAM)
INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "share/pixmaps/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
#Install global configuration files
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "../etc/openmw/" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
@ -325,8 +329,8 @@ if(DPKG_PROGRAM)
Data files from the original game is required to run it.")
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_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
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")
@ -346,6 +350,10 @@ if(WIN32)
FILE(GLOB files "${OpenMW_BINARY_DIR}/Release/*.*")
INSTALL(FILES ${files} DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
INSTALL(FILES
"${OpenMW_SOURCE_DIR}/readme.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg"
DESTINATION ".")
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
SET(CPACK_GENERATOR "NSIS")
@ -355,7 +363,12 @@ if(WIN32)
SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;esmtool;Esmtool;omwlauncher;OpenMW Launcher")
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;omwlauncher;OpenMW Launcher")
SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'")
SET(CPACK_NSIS_DELETE_ICONS_EXTRA "
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Readme.lnk\\\"
")
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt")
SET(CPACK_RESOURCE_FILE_LICENSE "${OpenMW_SOURCE_DIR}/GPL3.txt")
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
@ -409,6 +422,11 @@ if (BUILD_LAUNCHER)
add_subdirectory( apps/launcher )
endif()
option(BUILD_MWINIIMPORTER "build MWiniImporter inspector" ON)
if (BUILD_MWINIIMPORTER)
add_subdirectory( apps/mwiniimporter )
endif()
if (WIN32)
if (MSVC)
if (USE_DEBUG_CONSOLE)
@ -498,6 +516,7 @@ if (APPLE)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})

@ -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.

@ -95,5 +95,5 @@ else()
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}launcher.cfg")
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.cfg")
endif()

@ -222,10 +222,10 @@ 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("<br><b>Could not find the Data Files location</b><br><br> \
The directory containing the Data Files was not found.<br><br> \
The directory containing the data files was not found.<br><br> \
Press \"Browse...\" to specify the location manually.<br>"));
QAbstractButton *dirSelectButton =
@ -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<std::string>());
fileReader.open(iter->second.string());
try {
ESMReader fileReader;
QStringList availableMasters; // Will contain all found masters
fileReader.setEncoding(variables["encoding"].as<std::string>());
fileReader.open(iter->second.string());
// First we fill the availableMasters and the mMastersWidget
ESMReader::MasterList mlist = fileReader.getMasters();
// First we fill the availableMasters and the mMastersWidget
ESMReader::MasterList mlist = fileReader.getMasters();
for (unsigned int i = 0; i < mlist.size(); ++i) {
const QString currentMaster = QString::fromStdString(mlist[i].name);
availableMasters.append(currentMaster);
for (unsigned int i = 0; i < mlist.size(); ++i) {
const QString currentMaster = QString::fromStdString(mlist[i].name);
availableMasters.append(currentMaster);
const QList<QTableWidgetItem*> itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
const QList<QTableWidgetItem*> itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
if (itemList.isEmpty()) { // Master is not yet in the widget
mMastersWidget->insertRow(i);
if (itemList.isEmpty()) { // Master is not yet in the widget
mMastersWidget->insertRow(i);
QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
item->setForeground(Qt::red);
item->setFlags(item->flags() & ~(Qt::ItemIsSelectable));
QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
item->setForeground(Qt::red);
item->setFlags(item->flags() & ~(Qt::ItemIsSelectable));
mMastersWidget->setItem(i, 0, item);
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("<b>Author:</b> %1<br/> \
<b>Version:</b> %2<br/><br/> \
<b>Description:</b><br/> \
%3<br/><br/> \
<b>Created on:</b> %4<br/> \
<b>Last modified:</b> %5")
.arg(author)
.arg(version)
.arg(description)
.arg(fi.created().toString(Qt::TextDate))
.arg(fi.lastModified().toString(Qt::TextDate));
QString toolTip= QString("<b>Author:</b> %1<br/> \
<b>Version:</b> %2<br/><br/> \
<b>Description:</b><br/> \
%3<br/><br/> \
<b>Created on:</b> %4<br/> \
<b>Last modified:</b> %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<QStandardItem*> masterList = mDataFilesModel->findItems(availableMasters.join(","));
const QList<QStandardItem*> 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;
}
}
@ -1050,16 +1057,8 @@ void DataFilesPage::writeConfig(QString profile)
return;
}
// Prepare the OpenMW config
QString config = QString::fromStdString((mCfgMgr.getLocalPath() / "openmw.cfg").string());
QFile file(config);
if (!file.exists()) {
config = QString::fromStdString((mCfgMgr.getUserPath() / "openmw.cfg").string());
}
// Open the config as a QFile
file.setFileName(config);
// Open the OpenMW config as a QFile
QFile file(QString::fromStdString((mCfgMgr.getUserPath() / "openmw.cfg").string()));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
// File cannot be opened or created

@ -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()));
@ -175,6 +194,7 @@ void MainDialog::play()
QDir dir(QCoreApplication::applicationDirPath());
QString game = dir.absoluteFilePath("openmw");
QFile file(game);
game = "\"" + game + "\"";
#else
QString game = "./openmw";
QFile file(game);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 50 KiB

@ -0,0 +1,20 @@
set(MWINIIMPORT
main.cpp
importer.cpp
)
set(MWINIIMPORT_HEADER
importer.hpp
)
source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER})
add_executable(mwiniimport
${MWINIIMPORT}
)
target_link_libraries(mwiniimport
${Boost_LIBRARIES}
components
)

@ -0,0 +1,216 @@
#include "importer.hpp"
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <sstream>
MwIniImporter::MwIniImporter() {
const char *map[][2] =
{
{ "fps", "General:Show FPS" },
{ "nosound", "General:Disable Audio" },
{ 0, 0 }
};
const char *fallback[] = {
"Weather:Sunrise Time",
"Weather:Sunset Time",
0
};
for(int i=0; map[i][0]; i++) {
mMergeMap.insert(std::make_pair<std::string, std::string>(map[i][0], map[i][1]));
}
for(int i=0; fallback[i]; i++) {
mMergeFallback.push_back(fallback[i]);
}
}
void MwIniImporter::setVerbose(bool verbose) {
mVerbose = verbose;
}
std::string MwIniImporter::numberToString(int n) {
std::stringstream str;
str << n;
return str.str();
}
MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
std::cout << "load ini file: " << filename << std::endl;
std::string section("");
MwIniImporter::multistrmap map;
boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str());
std::string line;
while (std::getline(file, line)) {
if(line[0] == '[') {
if(line.length() > 2) {
section = line.substr(1, line.length()-3);
}
continue;
}
int comment_pos = line.find(";");
if(comment_pos > 0) {
line = line.substr(0,comment_pos);
}
if(line.empty()) {
continue;
}
int pos = line.find("=");
if(pos < 1) {
continue;
}
std::string key(section + ":" + line.substr(0,pos));
std::string value(line.substr(pos+1));
multistrmap::iterator it;
if((it = map.find(key)) == map.end()) {
map.insert( std::make_pair<std::string, std::vector<std::string> > (key, std::vector<std::string>() ) );
}
map[key].push_back(value);
}
return map;
}
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) {
std::cout << "load cfg file: " << filename << std::endl;
MwIniImporter::multistrmap map;
boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str());
std::string line;
while (std::getline(file, line)) {
// we cant say comment by only looking at first char anymore
int comment_pos = line.find("#");
if(comment_pos > 0) {
line = line.substr(0,comment_pos);
}
if(line.empty()) {
continue;
}
int pos = line.find("=");
if(pos < 1) {
continue;
}
std::string key(line.substr(0,pos));
std::string value(line.substr(pos+1));
multistrmap::iterator it;
if((it = map.find(key)) == map.end()) {
map.insert( std::make_pair<std::string, std::vector<std::string> > (key, std::vector<std::string>() ) );
}
map[key].push_back(value);
}
return map;
}
void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) {
multistrmap::iterator cfgIt;
multistrmap::iterator iniIt;
for(strmap::iterator it=mMergeMap.begin(); it!=mMergeMap.end(); it++) {
if((iniIt = ini.find(it->second)) != ini.end()) {
for(std::vector<std::string>::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); vc++) {
cfg.erase(it->first);
insertMultistrmap(cfg, it->first, *vc);
}
}
}
}
void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) {
cfg.erase("fallback");
multistrmap::iterator cfgIt;
multistrmap::iterator iniIt;
for(std::vector<std::string>::iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); it++) {
if((iniIt = ini.find(*it)) != ini.end()) {
for(std::vector<std::string>::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); vc++) {
std::string value(*it);
std::replace( value.begin(), value.end(), ' ', '_' );
std::replace( value.begin(), value.end(), ':', '_' );
value.append(",").append(vc->substr(0,vc->length()-1));
insertMultistrmap(cfg, "fallback", value);
}
}
}
};
void MwIniImporter::insertMultistrmap(multistrmap &cfg, std::string key, std::string value) {
multistrmap::iterator it = cfg.find(key);
if(it == cfg.end()) {
cfg.insert(std::make_pair<std::string, std::vector<std::string> >(key, std::vector<std::string>() ));
}
cfg[key].push_back(value);
}
void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
std::vector<std::string> esmFiles;
std::vector<std::string> espFiles;
std::string baseGameFile("Game Files:GameFile");
std::string gameFile("");
multistrmap::iterator it = ini.begin();
for(int i=0; it != ini.end(); i++) {
gameFile = baseGameFile;
gameFile.append(this->numberToString(i));
it = ini.find(gameFile);
if(it == ini.end()) {
break;
}
for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); entry++) {
std::string filetype(entry->substr(entry->length()-4, 3));
std::transform(filetype.begin(), filetype.end(), filetype.begin(), ::tolower);
if(filetype.compare("esm") == 0) {
esmFiles.push_back(*entry);
}
else if(filetype.compare("esp") == 0) {
espFiles.push_back(*entry);
}
}
gameFile = "";
}
cfg.erase("master");
cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("master", std::vector<std::string>() ) );
for(std::vector<std::string>::iterator it=esmFiles.begin(); it!=esmFiles.end(); it++) {
cfg["master"].push_back(*it);
}
cfg.erase("plugin");
cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("plugin", std::vector<std::string>() ) );
for(std::vector<std::string>::iterator it=espFiles.begin(); it!=espFiles.end(); it++) {
cfg["plugin"].push_back(*it);
}
}
void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg) {
for(multistrmap::iterator it=cfg.begin(); it != cfg.end(); it++) {
for(std::vector<std::string>::iterator entry=it->second.begin(); entry != it->second.end(); entry++) {
out << (it->first) << "=" << (*entry) << std::endl;
}
}
}

@ -0,0 +1,34 @@
#ifndef MWINIIMPORTER_IMPORTER
#define MWINIIMPORTER_IMPORTER 1
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
#include <string>
#include <map>
#include <vector>
#include <exception>
class MwIniImporter {
public:
typedef std::map<std::string, std::string> strmap;
typedef std::map<std::string, std::vector<std::string> > multistrmap;
MwIniImporter();
void setVerbose(bool verbose);
multistrmap loadIniFile(std::string filename);
multistrmap loadCfgFile(std::string filename);
void merge(multistrmap &cfg, multistrmap &ini);
void mergeFallback(multistrmap &cfg, multistrmap &ini);
void importGameFiles(multistrmap &cfg, multistrmap &ini);
void writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg);
private:
void insertMultistrmap(multistrmap &cfg, std::string key, std::string value);
std::string numberToString(int n);
bool mVerbose;
strmap mMergeMap;
std::vector<std::string> mMergeFallback;
};
#endif

@ -0,0 +1,75 @@
#include "importer.hpp"
#include <iostream>
#include <string>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
namespace bpo = boost::program_options;
int main(int argc, char *argv[]) {
bpo::options_description desc("Syntax: mwiniimporter <options> inifile configfile\nAllowed options");
bpo::positional_options_description p_desc;
desc.add_options()
("help,h", "produce help message")
("verbose,v", "verbose output")
("ini,i", bpo::value<std::string>(), "morrowind.ini file")
("cfg,c", bpo::value<std::string>(), "openmw.cfg file")
("output,o", bpo::value<std::string>()->default_value(""), "openmw.cfg file")
("game-files,g", "import esm and esp files")
;
p_desc.add("ini", 1).add("cfg", 1);
bpo::variables_map vm;
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
.options(desc)
.positional(p_desc)
.run();
bpo::store(parsed, vm);
if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
std::cout << desc;
return 0;
}
bpo::notify(vm);
std::string iniFile = vm["ini"].as<std::string>();
std::string cfgFile = vm["cfg"].as<std::string>();
// if no output is given, write back to cfg file
std::string outputFile(vm["output"].as<std::string>());
if(vm["output"].defaulted()) {
outputFile = vm["cfg"].as<std::string>();
}
if(!boost::filesystem::exists(iniFile)) {
std::cerr << "ini file does not exist" << std::endl;
return -3;
}
if(!boost::filesystem::exists(cfgFile)) {
std::cerr << "cfg file does not exist" << std::endl;
return -4;
}
MwIniImporter importer;
importer.setVerbose(vm.count("verbose"));
MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile);
MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile);
importer.merge(cfg, ini);
importer.mergeFallback(cfg, ini);
if(vm.count("game-files")) {
importer.importGameFiles(cfg, ini);
}
std::cout << "write to: " << outputFile << std::endl;
boost::iostreams::stream<boost::iostreams::file_sink> file(outputFile);
importer.writeToFile(file, cfg);
return 0;
}

@ -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 occlusionquery terrain terrainmaterial water
)
add_openmw_dir (mwinput
@ -24,6 +25,7 @@ add_openmw_dir (mwinput
add_openmw_dir (mwgui
layouts text_input widgets race class birth review window_manager console dialogue
dialogue_history window_base stats_window messagebox journalwindow charactercreation
map_window window_pinnable_base
)
add_openmw_dir (mwdialogue
@ -38,13 +40,13 @@ add_openmw_dir (mwscript
)
add_openmw_dir (mwsound
soundmanager
soundmanager openal_output audiere_decoder 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
@ -53,7 +55,7 @@ add_openmw_dir (mwclass
)
add_openmw_dir (mwmechanics
mechanicsmanager stat creaturestats magiceffects movement
mechanicsmanager stat creaturestats magiceffects movement actors
)
# Main executable
@ -81,17 +83,23 @@ add_definitions(${SOUND_DEFINE})
target_link_libraries(openmw
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${OGRE_Terrain_LIBRARY}
${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})

@ -20,6 +20,7 @@
#include <components/esm/esm_reader.hpp>
#include <components/files/fixedpath.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/settings/settings.hpp>
#include <components/nifbullet/bullet_nif_loader.hpp>
#include <components/nifogre/ogre_nif_loader.hpp>
@ -82,12 +83,20 @@ void OMW::Engine::updateFocusReport (float duration)
if (!handle.empty())
{
MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle);
// the faced handle is not updated immediately, so on a cell change it might
// point to an object that doesn't exist anymore
// therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case
try
{
MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle);
if (!ptr.isEmpty()){
name = MWWorld::Class::get (ptr).getName (ptr);
if (!ptr.isEmpty()){
name = MWWorld::Class::get (ptr).getName (ptr);
}
}
catch (std::runtime_error& e)
{}
}
if (name!=mFocusName)
@ -115,13 +124,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
{
mEnvironment.mFrameDuration = evt.timeSinceLastFrame;
// update input
mEnvironment.mInputManager->update();
// sound
if (mUseSound)
{
mEnvironment.mSoundManager->playPlaylist();
mEnvironment.mSoundManager->update (evt.timeSinceLastFrame);
}
// update GUI
Ogre::RenderWindow* window = mOgre->getWindow();
@ -152,7 +160,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
// update actors
std::vector<std::pair<std::string, Ogre::Vector3> > movement;
mEnvironment.mMechanicsManager->update (movement);
mEnvironment.mMechanicsManager->update (movement, mEnvironment.mFrameDuration,
mEnvironment.mWindowManager->getMode()!=MWGui::GM_Game);
if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game)
mEnvironment.mWorld->doPhysics (movement, mEnvironment.mFrameDuration);
@ -208,13 +217,18 @@ OMW::Engine::~Engine()
void OMW::Engine::loadBSA()
{
const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa");
std::string dataDirectory;
for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter)
{
std::cout << "Adding " << iter->second.string() << std::endl;
Bsa::addBSA(iter->second.string());
}
dataDirectory = iter->second.parent_path().string();
const Files::PathContainer& dataDirs = mFileCollections.getPaths();
std::string dataDirectory;
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
dataDirectory = iter->string();
std::cout << "Data dir " << dataDirectory << std::endl;
Bsa::addDir(dataDirectory, mFSStrict);
}
@ -312,6 +326,29 @@ void OMW::Engine::go()
{
boost::filesystem::create_directories(configPath);
}
// Create the settings manager and load default settings file
Settings::Manager settings;
const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg";
const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg";
// prefer local
if (boost::filesystem::exists(localdefault))
settings.loadDefault(localdefault);
else if (boost::filesystem::exists(globaldefault))
settings.loadDefault(globaldefault);
// load user settings if they exist, otherwise just load the default settings as user settings
const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg";
if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath);
else if (boost::filesystem::exists(localdefault))
settings.loadUser(localdefault);
else if (boost::filesystem::exists(globaldefault))
settings.loadUser(globaldefault);
mFpsLevel = settings.getInt("fps", "HUD");
mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()),
mCfgMgr.getOgreConfigPath().string(),
mCfgMgr.getLogPath().string(),
@ -319,7 +356,11 @@ void OMW::Engine::go()
// This has to be added BEFORE MyGUI is initialized, as it needs
// to find core.xml here.
//addResourcesDirectory(mResDir);
addResourcesDirectory(mResDir / "mygui");
addResourcesDirectory(mResDir / "water");
// Create the window
mOgre->createWindow("OpenMW");
@ -328,7 +369,7 @@ void OMW::Engine::go()
// Create the world
mEnvironment.mWorld = new MWWorld::World (*mOgre, mFileCollections, mMaster,
mResDir, mNewGame, mEnvironment, mEncoding);
mResDir, mNewGame, mEnvironment, mEncoding, mFallbackMap);
// Create window manager - this manages all the MW-specific GUI windows
MWScript::registerExtensions (mExtensions);
@ -337,10 +378,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,
@ -405,6 +443,9 @@ void OMW::Engine::go()
// Start the main rendering loop
mOgre->start();
// Save user settings
settings.saveUser(settingspath);
std::cout << "Quitting peacefully.\n";
}
@ -418,10 +459,21 @@ void OMW::Engine::activate()
if (handle.empty())
return;
MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle);
// the faced handle is not updated immediately, so on a cell change it might
// point to an object that doesn't exist anymore
// therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case
MWWorld::Ptr ptr;
try
{
ptr = mEnvironment.mWorld->getPtrViaHandle (handle);
if (ptr.isEmpty())
if (ptr.isEmpty())
return;
}
catch (std::runtime_error&)
{
return;
}
MWScript::InterpreterContext interpreterContext (mEnvironment,
&ptr.getRefData().getLocals(), ptr);
@ -487,3 +539,8 @@ void OMW::Engine::setEncoding(const std::string& encoding)
{
mEncoding = encoding;
}
void OMW::Engine::setFallbackValues(std::map<std::string,std::string> fallbackMap)
{
mFallbackMap = fallbackMap;
}

@ -76,6 +76,7 @@ namespace OMW
bool mReportFocus;
float mFocusTDiff;
std::string mFocusName;
std::map<std::string,std::string> mFallbackMap;
MWWorld::Environment mEnvironment;
Compiler::Extensions mExtensions;
@ -163,6 +164,8 @@ namespace OMW
void setAnimationVerbose(bool animverbose);
void setFallbackValues(std::map<std::string,std::string> map);
private:
Files::ConfigurationManager& mCfgMgr;
};

@ -54,6 +54,41 @@ inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string
using namespace std;
struct FallbackMap {
std::map<std::string,std::string> mMap;
};
void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
{
if(v.empty())
{
v = boost::any(FallbackMap());
}
FallbackMap *map = boost::any_cast<FallbackMap>(&v);
std::map<std::string,std::string>::iterator mapIt;
for(std::vector<std::string>::const_iterator it=tokens.begin(); it != tokens.end(); it++)
{
int sep = it->find(",");
if(sep < 1 || sep == (int)it->length()-1)
#if (BOOST_VERSION < 104200)
throw boost::program_options::validation_error("invalid value");
#else
throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value);
#endif
std::string key(it->substr(0,sep));
std::string value(it->substr(sep+1));
if((mapIt = map->mMap.find(key)) == map->mMap.end())
{
map->mMap.insert(std::make_pair<std::string,std::string>(key,value));
}
}
}
/**
* \brief Parses application command line and calls \ref Cfg::ConfigurationManager
* to parse configuration files.
@ -92,39 +127,40 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("plugin", bpo::value<StringsVector>()->default_value(StringsVector(), "")
->multitoken(), "plugin file(s)")
("fps", boost::program_options::value<int>()->implicit_value(1)
->default_value(0), "fps counter detail (0 = off, 1 = fps counter, 2 = full detail)")
("anim-verbose", boost::program_options::value<bool>()->implicit_value(true)
("anim-verbose", bpo::value<bool>()->implicit_value(true)
->default_value(false), "output animation indices files")
("debug", boost::program_options::value<bool>()->implicit_value(true)
("debug", bpo::value<bool>()->implicit_value(true)
->default_value(false), "debug mode")
("nosound", boost::program_options::value<bool>()->implicit_value(true)
("nosound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "disable all sounds")
("script-verbose", boost::program_options::value<bool>()->implicit_value(true)
("script-verbose", bpo::value<bool>()->implicit_value(true)
->default_value(false), "verbose script output")
("new-game", boost::program_options::value<bool>()->implicit_value(true)
("new-game", bpo::value<bool>()->implicit_value(true)
->default_value(false), "activate char gen/new game mechanics")
("script-all", boost::program_options::value<bool>()->implicit_value(true)
("script-all", bpo::value<bool>()->implicit_value(true)
->default_value(false), "compile all scripts (excluding dialogue scripts) at startup")
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)
("fs-strict", bpo::value<bool>()->implicit_value(true)
->default_value(false), "strict file system handling (no case folding)")
( "encoding", boost::program_options::value<std::string>()->
( "encoding", bpo::value<std::string>()->
default_value("win1252"),
"Character encoding used in OpenMW game messages:\n"
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
"\n\twin1252 - Western European (Latin) alphabet, used by default")
("report-focus", boost::program_options::value<bool>()->implicit_value(true)
("report-focus", bpo::value<bool>()->implicit_value(true)
->default_value(false), "write name of focussed object to cout")
("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
->multitoken()->composing(), "fallback values")
;
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
@ -225,13 +261,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setNewGame(variables["new-game"].as<bool>());
// other settings
engine.showFPS(variables["fps"].as<int>());
engine.setDebugMode(variables["debug"].as<bool>());
engine.setSoundUsage(!variables["nosound"].as<bool>());
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
engine.setCompileAll(variables["script-all"].as<bool>());
engine.setReportFocus(variables["report-focus"].as<bool>());
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
return true;
}

@ -56,7 +56,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -70,6 +70,14 @@ namespace MWClass
return ref->base->script;
}
int Apparatus::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Apparatus, MWWorld::RefData> *ref =
ptr.get<ESM::Apparatus>();
return ref->base->data.value;
}
void Apparatus::registerSelf()
{
boost::shared_ptr<Class> instance (new Apparatus);

@ -25,6 +25,9 @@ namespace MWClass
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const;

@ -60,7 +60,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -160,6 +160,14 @@ namespace MWClass
return ESM::Skill::HeavyArmor;
}
int Armor::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Armor, MWWorld::RefData> *ref =
ptr.get<ESM::Armor>();
return ref->base->data.value;
}
void Armor::registerSelf()
{
boost::shared_ptr<Class> instance (new Armor);

@ -40,6 +40,9 @@ namespace MWClass
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
/// no such skill.
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -58,7 +58,7 @@ namespace MWClass
{
// TODO implement reading
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -72,6 +72,14 @@ namespace MWClass
return ref->base->script;
}
int Book::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Book, MWWorld::RefData> *ref =
ptr.get<ESM::Book>();
return ref->base->data.value;
}
void Book::registerSelf()
{
boost::shared_ptr<Class> instance (new Book);

@ -25,6 +25,9 @@ namespace MWClass
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -57,7 +57,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -123,6 +123,14 @@ namespace MWClass
return -1;
}
int Clothing::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
ptr.get<ESM::Clothing>();
return ref->base->data.value;
}
void Clothing::registerSelf()
{
boost::shared_ptr<Class> instance (new Clothing);

@ -34,6 +34,9 @@ namespace MWClass
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
/// no such skill.
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -85,7 +85,7 @@ namespace MWClass
{
// TODO check for key
std::cout << "Locked container" << std::endl;
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false);
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
else
@ -100,7 +100,7 @@ namespace MWClass
{
// Trap activation goes here
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0, false);
environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0);
ptr.getCellRef().trap = "";
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}

@ -73,7 +73,7 @@ namespace MWClass
// TODO check for key
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
std::cout << "Locked!" << std::endl;
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false);
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
@ -81,7 +81,7 @@ namespace MWClass
{
// Trap activation
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0, false);
environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0);
ptr.getCellRef().trap = "";
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
@ -110,7 +110,7 @@ namespace MWClass
// TODO return action for rotating the door
// This is a little pointless, but helps with testing
environment.mSoundManager->playSound3D (ptr, openSound, 1.0, 1.0, false);
environment.mSoundManager->playSound3D (ptr, openSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
}

@ -54,7 +54,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -68,6 +68,14 @@ namespace MWClass
return ref->base->script;
}
int Ingredient::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Ingredient, MWWorld::RefData> *ref =
ptr.get<ESM::Ingredient>();
return ref->base->data.value;
}
void Ingredient::registerSelf()
{
boost::shared_ptr<Class> instance (new Ingredient);

@ -25,6 +25,9 @@ namespace MWClass
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -59,7 +59,7 @@ namespace MWClass
if (!ref->base->sound.empty())
{
environment.mSoundManager->playSound3D (ptr, ref->base->sound, 1.0, 1.0, true);
environment.mSoundManager->playSound3D (ptr, ref->base->sound, 1.0, 1.0, MWSound::Play_Loop);
}
}
@ -83,7 +83,7 @@ namespace MWClass
if (!(ref->base->data.flags & ESM::Light::Carry))
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -110,6 +110,14 @@ namespace MWClass
return std::make_pair (slots, false);
}
int Light::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =
ptr.get<ESM::Light>();
return ref->base->data.value;
}
void Light::registerSelf()
{
boost::shared_ptr<Class> instance (new Light);

@ -34,6 +34,9 @@ namespace MWClass
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
/// stay stacked when equipped?
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -58,7 +58,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -81,6 +81,14 @@ namespace MWClass
return std::make_pair (slots, false);
}
int Lockpick::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Tool, MWWorld::RefData> *ref =
ptr.get<ESM::Tool>();
return ref->base->data.value;
}
void Lockpick::registerSelf()
{
boost::shared_ptr<Class> instance (new Lockpick);

@ -29,6 +29,9 @@ namespace MWClass
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
/// stay stacked when equipped?
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -56,7 +56,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -70,6 +70,14 @@ namespace MWClass
return ref->base->script;
}
int Miscellaneous::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData> *ref =
ptr.get<ESM::Miscellaneous>();
return ref->base->data.value;
}
void Miscellaneous::registerSelf()
{
boost::shared_ptr<Class> instance (new Miscellaneous);

@ -25,6 +25,9 @@ namespace MWClass
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -56,7 +56,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -70,6 +70,14 @@ namespace MWClass
return ref->base->script;
}
int Potion::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Potion, MWWorld::RefData> *ref =
ptr.get<ESM::Potion>();
return ref->base->data.value;
}
void Potion::registerSelf()
{
boost::shared_ptr<Class> instance (new Potion);

@ -25,6 +25,9 @@ namespace MWClass
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -57,7 +57,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -80,6 +80,14 @@ namespace MWClass
return std::make_pair (slots, false);
}
int Probe::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Probe, MWWorld::RefData> *ref =
ptr.get<ESM::Probe>();
return ref->base->data.value;
}
void Probe::registerSelf()
{
boost::shared_ptr<Class> instance (new Probe);

@ -29,6 +29,9 @@ namespace MWClass
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
/// stay stacked when equipped?
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -56,7 +56,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -70,6 +70,14 @@ namespace MWClass
return ref->base->script;
}
int Repair::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Repair, MWWorld::RefData> *ref =
ptr.get<ESM::Repair>();
return ref->base->data.value;
}
void Repair::registerSelf()
{
boost::shared_ptr<Class> instance (new Repair);

@ -25,6 +25,9 @@ namespace MWClass
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -57,7 +57,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr));
@ -139,6 +139,14 @@ namespace MWClass
return -1;
}
int Weapon::getValue (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
ptr.get<ESM::Weapon>();
return ref->base->data.value;
}
void Weapon::registerSelf()
{
boost::shared_ptr<Class> instance (new Weapon);

@ -40,6 +40,9 @@ namespace MWClass
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
/// no such skill.
virtual int getValue (const MWWorld::Ptr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded.
static void registerSelf();
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;

@ -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<ESM::DialInfo::SelectStruct>::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<int,int>(comp,mChoice,select.i)) return false;
@ -516,7 +513,6 @@ namespace MWDialogue
return false;
// TODO check DATAstruct
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator iter (info.selects.begin());
iter != info.selects.end(); ++iter)
if (!isMatching (actor, *iter))
@ -532,6 +528,13 @@ namespace MWDialogue
mChoice = -1;
mIsInChoice = false;
mCompilerContext.setExtensions (&extensions);
mDialogueMap.clear();
actorKnownTopics.clear();
ESMS::RecListT<ESM::Dialogue>::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list;
for(ESMS::RecListT<ESM::Dialogue>::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++)
{
mDialogueMap[it->first] = it->second;
}
}
void DialogueManager::addTopic(std::string topic)
@ -567,13 +570,7 @@ namespace MWDialogue
mActor = actor;
mDialogueMap.clear();
actorKnownTopics.clear();
ESMS::RecListT<ESM::Dialogue>::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list;
for(ESMS::RecListT<ESM::Dialogue>::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++)
{
mDialogueMap[it->first] = it->second;
}
//initialise the GUI
mEnvironment.mInputManager->setGuiMode(MWGui::GM_Dialogue);
@ -586,6 +583,7 @@ namespace MWDialogue
//greeting
bool greetingFound = false;
//ESMS::RecListT<ESM::Dialogue>::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list;
ESMS::RecListT<ESM::Dialogue>::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list;
for(ESMS::RecListT<ESM::Dialogue>::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++)
{
ESM::Dialogue ndialogue = it->second;
@ -680,7 +678,8 @@ namespace MWDialogue
void DialogueManager::updateTopics()
{
std::list<std::string> keywordList;
int choice = mChoice;
mChoice = -1;
actorKnownTopics.clear();
MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow();
ESMS::RecListT<ESM::Dialogue>::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list;
@ -692,7 +691,7 @@ namespace MWDialogue
for (std::vector<ESM::DialInfo>::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 +705,7 @@ namespace MWDialogue
}
}
win->setKeywords(keywordList);
mChoice = choice;
}
void DialogueManager::keywordSelected(std::string keyword)
@ -715,10 +715,9 @@ namespace MWDialogue
if(mDialogueMap.find(keyword) != mDialogueMap.end())
{
ESM::Dialogue ndialogue = mDialogueMap[keyword];
std::vector<ESM::DialInfo>::const_iterator iter;
if(ndialogue.type == ESM::Dialogue::Topic)
{
for (iter = ndialogue.mInfo.begin();
for (std::vector<ESM::DialInfo>::const_iterator iter = ndialogue.mInfo.begin();
iter!=ndialogue.mInfo.end(); ++iter)
{
if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true))
@ -742,6 +741,7 @@ namespace MWDialogue
}
}
}
updateTopics();
}

@ -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<MyGUI::StaticText>("SandBrightText", coord, MyGUI::Align::Default, std::string("Label"));
MyGUI::TextBox* label = spellArea->createWidget<MyGUI::TextBox>("SandBrightText", coord, MyGUI::Align::Default, std::string("Label"));
label->setCaption(mWindowManager.getGameSettingString(categories[category].label, ""));
spellItems.push_back(label);
coord.top += lineHeight;

@ -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<MyGUI::WidgetPtr> spellItems;
std::string currentBirthId;

@ -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();
}

@ -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<Widgets::MWSkillPtr>::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

@ -31,7 +31,7 @@ namespace MWGui
int getChosenButton() const;
// Events
typedef delegates::CDelegate1<int> EventHandle_Int;
typedef delegates::CMultiDelegate1<int> 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<MyGUI::ButtonPtr> 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];

@ -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)

@ -43,24 +43,28 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environm
// Centre dialog
center();
//WindowManager *wm = environment.mWindowManager;
setText("NpcName", "Name of character");
//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 +72,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 +103,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;
@ -109,7 +113,8 @@ void DialogueWindow::onSelectTopic(MyGUI::List* _sender, size_t _index)
void DialogueWindow::startDialogue(std::string npcName)
{
setText("NpcName", npcName);
static_cast<MyGUI::Window*>(mMainWidget)->setCaption(npcName);
adjustWindowCaption();
}
void DialogueWindow::setKeywords(std::list<std::string> keyWords)

@ -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<std::string,std::string> pTopicsText;// this map links keyword and "real" text.

@ -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");

@ -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);

@ -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<MyGUI::WindowPtr>(mMainWidget);
t->eventWindowChangeCoord = MyGUI::newDelegate(this, &JournalWindow::onWindowResize);
t->eventWindowChangeCoord += MyGUI::newDelegate(this, &JournalWindow::onWindowResize);
}
void MWGui::JournalWindow::open()

@ -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
#endif

@ -15,6 +15,27 @@ 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)
, hmsBaseLeft(0)
, weapBoxBaseLeft(0)
, spellBoxBaseLeft(0)
, effectBoxBaseRight(0)
, minimapBoxBaseRight(0)
{
setCoord(0,0, width, height);
@ -22,16 +43,25 @@ HUD::HUD(int width, int height, int fpsLevel)
getWidget(health, "Health");
getWidget(magicka, "Magicka");
getWidget(stamina, "Stamina");
hmsBaseLeft = health->getLeft();
// Item and spell images and status bars
getWidget(weapBox, "WeapBox");
getWidget(weapImage, "WeapImage");
getWidget(weapStatus, "WeapStatus");
weapBoxBaseLeft = weapBox->getLeft();
getWidget(spellBox, "SpellBox");
getWidget(spellImage, "SpellImage");
getWidget(spellStatus, "SpellStatus");
spellBoxBaseLeft = spellBox->getLeft();
getWidget(effectBox, "EffectBox");
getWidget(effect1, "Effect1");
effectBoxBaseRight = effectBox->getRight();
getWidget(minimapBox, "MiniMapBox");
minimapBoxBaseRight = minimapBox->getRight();
getWidget(minimap, "MiniMap");
getWidget(compass, "Compass");
@ -61,6 +91,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 +174,146 @@ void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<int>& v
}
}
}
void HUD::setPlayerDir(const float x, const float y)
{
if (!minimapBox->getVisible() || (x == mLastPositionX && y == mLastPositionY)) return;
MyGUI::ISubWidget* main = compass->getSubWidgetMain();
MyGUI::RotatingSkin* rotatingSubskin = main->castType<MyGUI::RotatingSkin>();
rotatingSubskin->setCenter(MyGUI::IntPoint(16,16));
float angle = std::atan2(x,y);
rotatingSubskin->setAngle(angle);
mLastPositionX = x;
mLastPositionY = y;
}
void HUD::setPlayerPos(const float x, const float y)
{
if (!minimapBox->getVisible() || (x == mLastDirectionX && y == mLastDirectionY)) return;
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));
mLastDirectionX = x;
mLastDirectionY = y;
}
void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible)
{
int weapDx = 0, spellDx = 0;
if (!hmsVisible)
spellDx = weapDx = weapBoxBaseLeft - hmsBaseLeft;
if (!weapVisible)
spellDx -= spellBoxBaseLeft - weapBoxBaseLeft;
health->setVisible(hmsVisible);
stamina->setVisible(hmsVisible);
magicka->setVisible(hmsVisible);
weapBox->setPosition(weapBoxBaseLeft - weapDx, weapBox->getTop());
weapBox->setVisible(weapVisible);
spellBox->setPosition(spellBoxBaseLeft - spellDx, spellBox->getTop());
spellBox->setVisible(spellVisible);
}
void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible)
{
// effect box can have variable width -> variable left coordinate
int effectsDx = 0;
if (!minimapBoxVisible)
effectsDx = minimapBoxBaseRight - effectBoxBaseRight;
minimapBox->setVisible(minimapBoxVisible);
effectBox->setPosition(effectBoxBaseRight - effectBox->getWidth() + effectsDx, effectBox->getTop());
effectBox->setVisible(effectBoxVisible);
}
LocalMapBase::LocalMapBase()
: mCurX(0)
, mCurY(0)
, mInterior(false)
, mFogOfWar(true)
, mLocalMap(NULL)
, mPrefix()
, mChanged(true)
, mLayout(NULL)
, mLastPositionX(0.0f)
, mLastPositionY(0.0f)
, mLastDirectionX(0.0f)
, mLastDirectionY(0.0f)
{
}
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::toggleFogOfWar()
{
mFogOfWar = !mFogOfWar;
applyFogOfWar();
}
void LocalMapBase::applyFogOfWar()
{
for (int mx=0; mx<3; ++mx)
{
for (int my=0; my<3; ++my)
{
std::string name = "Map_" + boost::lexical_cast<std::string>(mx) + "_"
+ boost::lexical_cast<std::string>(my);
std::string image = mPrefix+"_"+ boost::lexical_cast<std::string>(mCurX + (mx-1)) + "_"
+ boost::lexical_cast<std::string>(mCurY + (mInterior ? (my-1) : -1*(my-1)));
MyGUI::ImageBox* fog;
mLayout->getWidget(fog, name+"_fog");
fog->setImageTexture(mFogOfWar ?
((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog"
: "black.png" )
: "");
}
}
}
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<std::string>(mx) + "_"
+ boost::lexical_cast<std::string>(my);
std::string image = mPrefix+"_"+ boost::lexical_cast<std::string>(x + (mx-1)) + "_"
+ boost::lexical_cast<std::string>(y + (interior ? (my-1) : -1*(my-1)));
MyGUI::ImageBox* box;
mLayout->getWidget(box, name);
if (MyGUI::RenderManager::getInstance().getTexture(image) != 0)
box->setImageTexture(image);
else
box->setImageTexture("black.png");
}
}
mInterior = interior;
mCurX = x;
mCurY = y;
mChanged = false;
applyFogOfWar();
}

@ -14,6 +14,8 @@
#include "../mwmechanics/stat.hpp"
#include "window_base.hpp"
#include <cmath>
/*
This file contains classes corresponding to window layouts
defined in resources/mygui/ *.xml.
@ -29,7 +31,36 @@
namespace MWGui
{
class HUD : public OEngine::GUI::Layout
class LocalMapBase
{
public:
LocalMapBase();
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);
void toggleFogOfWar();
protected:
int mCurX, mCurY;
bool mInterior;
MyGUI::ScrollView* mLocalMap;
std::string mPrefix;
bool mChanged;
bool mFogOfWar;
void applyFogOfWar();
OEngine::GUI::Layout* mLayout;
float mLastPositionX;
float mLastPositionY;
float mLastDirectionX;
float mLastDirectionY;
};
class HUD : public OEngine::GUI::Layout, public LocalMapBase
{
public:
HUD(int width, int height, int fpsLevel);
@ -43,40 +74,31 @@ 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);
void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible);
void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible);
MyGUI::ProgressPtr health, magicka, stamina;
MyGUI::StaticImagePtr weapImage, spellImage;
MyGUI::Widget *weapBox, *spellBox;
MyGUI::ImageBox *weapImage, *spellImage;
MyGUI::ProgressPtr weapStatus, spellStatus;
MyGUI::WidgetPtr effectBox;
MyGUI::StaticImagePtr effect1;
MyGUI::StaticImagePtr minimap;
MyGUI::StaticImagePtr compass;
MyGUI::StaticImagePtr crosshair;
MyGUI::Widget *effectBox, *minimapBox;
MyGUI::ImageBox* effect1;
MyGUI::ScrollView* minimap;
MyGUI::ImageBox* compass;
MyGUI::ImageBox* crosshair;
MyGUI::WidgetPtr fpsbox;
MyGUI::StaticTextPtr fpscounter;
MyGUI::StaticTextPtr trianglecounter;
MyGUI::StaticTextPtr batchcounter;
};
class MapWindow : public OEngine::GUI::Layout
{
public:
MapWindow()
: Layout("openmw_map_window_layout.xml")
{
setCoord(500,0,320,300);
setText("WorldButton", "World");
setImage("Compass", "compass.dds");
// Obviously you should override this later on
setCellName("No Cell Loaded");
}
void setCellName(const std::string& cellName)
{
mMainWidget->setCaption(cellName);
}
MyGUI::TextBox* fpscounter;
MyGUI::TextBox* trianglecounter;
MyGUI::TextBox* batchcounter;
private:
// bottom left elements
int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft;
// bottom right elements
int minimapBoxBaseRight, effectBoxBaseRight;
};
class MainMenu : public OEngine::GUI::Layout
@ -127,7 +149,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 +187,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);
}
}

@ -0,0 +1,106 @@
#include "map_window.hpp"
#include "window_manager.hpp"
/*
#include "../mwmechanics/mechanicsmanager.hpp"
#include <cmath>
#include <algorithm>
#include <iterator>
#undef min
#undef max
*/
using namespace MWGui;
MapWindow::MapWindow(WindowManager& parWindowManager) :
MWGui::WindowPinnableBase("openmw_map_window_layout.xml", parWindowManager),
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::setCellName(const std::string& cellName)
{
static_cast<MyGUI::Window*>(mMainWidget)->setCaption(cellName);
adjustWindowCaption();
}
void MapWindow::setPlayerPos(const float x, const float y)
{
if (mGlobal || !mVisible || (x == mLastPositionX && y == mLastPositionY)) 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));
mLastPositionX = x;
mLastPositionY = y;
}
void MapWindow::setPlayerDir(const float x, const float y)
{
if (!mVisible || (x == mLastDirectionX && y == mLastDirectionY)) return;
MyGUI::ISubWidget* main = mPlayerArrow->getSubWidgetMain();
MyGUI::RotatingSkin* rotatingSubskin = main->castType<MyGUI::RotatingSkin>();
rotatingSubskin->setCenter(MyGUI::IntPoint(16,16));
float angle = std::atan2(x,y);
rotatingSubskin->setAngle(angle);
mLastDirectionX = x;
mLastDirectionY = y;
}
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 MapWindow::onPinToggled()
{
mWindowManager.setMinimapVisibility(!mPinned);
}

@ -0,0 +1,34 @@
#ifndef MWGUI_MAPWINDOW_H
#define MWGUI_MAPWINDOW_H
#include "layouts.hpp"
#include "window_pinnable_base.hpp"
namespace MWGui
{
class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase
{
public:
MapWindow(WindowManager& parWindowManager);
virtual ~MapWindow(){}
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);
MyGUI::ScrollView* mGlobalMap;
MyGUI::ImageBox* mPlayerArrow;
MyGUI::Button* mButton;
MyGUI::IntPoint mLastDragPos;
bool mGlobal;
protected:
virtual void onPinToggled();
};
}
#endif

@ -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<MessageBox*>::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::string> (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<std::string>::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<MyGUI::ButtonPtr>::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<MyGUI::ButtonPtr>::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;
}

@ -7,6 +7,7 @@
#include "window_base.hpp"
#include "window_manager.hpp"
#undef MessageBox
namespace MWGui
{

@ -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;

@ -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<MyGUI::WidgetPtr> skillItems;

@ -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<float>()));
skillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::StaticText*> (0)));
skillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::TextBox*> (0)));
}
static_cast<MyGUI::WindowPtr>(mMainWidget)->eventWindowChangeCoord = MyGUI::newDelegate(this, &ReviewDialog::onWindowResize);
static_cast<MyGUI::WindowPtr>(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<float>& 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<int>& 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<MyGUI::StaticImage>("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default);
MyGUI::ImageBox* separator = skillClientWidget->createWidget<MyGUI::ImageBox>("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<MyGUI::StaticText>("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default);
MyGUI::TextBox* groupWidget = skillClientWidget->createWidget<MyGUI::TextBox>("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<MyGUI::StaticText>("SandText", coord1, MyGUI::Align::Default);
skillNameWidget = skillClientWidget->createWidget<MyGUI::TextBox>("SandText", coord1, MyGUI::Align::Default);
skillNameWidget->setCaption(text);
skillValueWidget = skillClientWidget->createWidget<MyGUI::StaticText>("SandTextRight", coord2, MyGUI::Align::Default);
skillValueWidget = skillClientWidget->createWidget<MyGUI::TextBox>("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<MyGUI::StaticText>("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
skillNameWidget = skillClientWidget->createWidget<MyGUI::TextBox>("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<std::string>(static_cast<int>(modified)), style, coord1, coord2);
MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast<std::string>(static_cast<int>(modified)), style, coord1, coord2);
skillWidgetMap[skillId] = widget;
}
}

@ -49,8 +49,8 @@ namespace MWGui
void open();
// Events
typedef delegates::CDelegate0 EventHandle_Void;
typedef delegates::CDelegate1<int> EventHandle_Int;
typedef delegates::CMultiDelegate0 EventHandle_Void;
typedef delegates::CMultiDelegate1<int> 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<int, MWMechanics::Stat<float> > skillValues;
std::map<int, MyGUI::StaticTextPtr> skillWidgetMap;
std::map<int, MyGUI::TextBox*> skillWidgetMap;
std::string name, raceId, birthSignId;
ESM::Class klass;
std::vector<MyGUI::WidgetPtr> skillWidgets; //< Skills and other information

@ -12,10 +12,23 @@ using namespace MWGui;
const int StatsWindow::lineHeight = 18;
StatsWindow::StatsWindow (WindowManager& parWindowManager)
: WindowBase("openmw_stats_window_layout.xml", parWindowManager)
: WindowPinnableBase("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<int, MWMechanics::Stat<float> >(i, MWMechanics::Stat<float>()));
skillWidgetMap.insert(std::pair<int, MyGUI::StaticTextPtr>(i, nullptr));
skillWidgetMap.insert(std::pair<int, MyGUI::TextBox*>(i, nullptr));
}
MyGUI::WindowPtr t = static_cast<MyGUI::WindowPtr>(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<MyGUI::Window*>(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<float>& 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<MyGUI::StaticImage>("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default);
MyGUI::ImageBox* separator = skillClientWidget->createWidget<MyGUI::ImageBox>("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<MyGUI::StaticText>("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default);
MyGUI::TextBox* groupWidget = skillClientWidget->createWidget<MyGUI::TextBox>("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<MyGUI::StaticText>("SandText", coord1, MyGUI::Align::Default);
skillNameWidget = skillClientWidget->createWidget<MyGUI::TextBox>("SandText", coord1, MyGUI::Align::Default);
skillNameWidget->setCaption(text);
skillValueWidget = skillClientWidget->createWidget<MyGUI::StaticText>("SandTextRight", coord2, MyGUI::Align::Default);
skillValueWidget = skillClientWidget->createWidget<MyGUI::TextBox>("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<MyGUI::StaticText>("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
skillNameWidget = skillClientWidget->createWidget<MyGUI::TextBox>("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<std::string>(static_cast<int>(modified)), style, coord1, coord2);
MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast<std::string>(static_cast<int>(modified)), style, coord1, coord2);
skillWidgetMap[skillId] = widget;
}
}
@ -368,3 +381,8 @@ void StatsWindow::updateScroller()
skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0));
skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0));
}
void StatsWindow::onPinToggled()
{
mWindowManager.setHMSVisibility(!mPinned);
}

@ -9,13 +9,13 @@
#include <utility>
#include "../mwmechanics/stat.hpp"
#include "window_base.hpp"
#include "window_pinnable_base.hpp"
namespace MWGui
{
class WindowManager;
class StatsWindow : public WindowBase
class StatsWindow : public WindowPinnableBase
{
public:
typedef std::pair<std::string, int> Faction;
@ -49,31 +49,34 @@ 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<int, MWMechanics::Stat<float> > skillValues;
std::map<int, MyGUI::StaticTextPtr> skillWidgetMap;
std::map<int, MyGUI::TextBox*> skillWidgetMap;
std::map<std::string, MyGUI::WidgetPtr> factionWidgetMap;
FactionList factions; ///< Stores a list of factions and the current rank
std::string birthSignId;
int reputation, bounty;
std::vector<MyGUI::WidgetPtr> skillWidgets; //< Skills and other information
protected:
virtual void onPinToggled();
};
}
#endif

@ -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);

@ -62,24 +62,24 @@ void MWSkill::updateWidgets()
{
if (skillId == ESM::Skill::Length)
{
skillNameWidget->setCaption("");
static_cast<MyGUI::TextBox*>(skillNameWidget)->setCaption("");
}
else
{
const std::string &name = manager->getGameSettingString(ESM::Skill::sSkillNameIds[skillId], "");
skillNameWidget->setCaption(name);
static_cast<MyGUI::TextBox*>(skillNameWidget)->setCaption(name);
}
}
if (skillValueWidget)
{
SkillValue::Type modified = value.getModified(), base = value.getBase();
skillValueWidget->setCaption(boost::lexical_cast<std::string>(modified));
static_cast<MyGUI::TextBox*>(skillValueWidget)->setCaption(boost::lexical_cast<std::string>(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<std::string>();
if (name == "StatName")
{
MYGUI_DEBUG_ASSERT( ! skillNameWidget, "widget already assigned");
skillNameWidget = (*iter)->castType<StaticText>();
}
else if (name == "StatValue")
{
MYGUI_DEBUG_ASSERT( ! skillValueWidget, "widget already assigned");
skillValueWidget = (*iter)->castType<StaticText>();
}
else if (name == "StatNameButton")
{
MYGUI_DEBUG_ASSERT( ! skillNameWidget, "widget already assigned");
MyGUI::ButtonPtr button = (*iter)->castType<Button>();
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<Button>();
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<MyGUI::TextBox*>(attributeNameWidget)->setCaption("");
}
else
{
@ -191,75 +164,48 @@ void MWAttribute::updateWidgets()
"sAttributeLuck"
};
const std::string &name = manager->getGameSettingString(attributes[id], "");
attributeNameWidget->setCaption(name);
static_cast<MyGUI::TextBox*>(attributeNameWidget)->setCaption(name);
}
}
if (attributeValueWidget)
{
AttributeValue::Type modified = value.getModified(), base = value.getBase();
attributeValueWidget->setCaption(boost::lexical_cast<std::string>(modified));
static_cast<MyGUI::TextBox*>(attributeValueWidget)->setCaption(boost::lexical_cast<std::string>(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<std::string>();
if (name == "StatName")
{
MYGUI_DEBUG_ASSERT( ! attributeNameWidget, "widget already assigned");
attributeNameWidget = (*iter)->castType<StaticText>();
}
else if (name == "StatValue")
{
MYGUI_DEBUG_ASSERT( ! attributeValueWidget, "widget already assigned");
attributeValueWidget = (*iter)->castType<StaticText>();
}
else if (name == "StatNameButton")
{
MYGUI_DEBUG_ASSERT( ! attributeNameWidget, "widget already assigned");
MyGUI::ButtonPtr button = (*iter)->castType<Button>();
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<Button>();
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<MyGUI::TextBox*>(spellNameWidget)->setCaption(spell->name);
else
spellNameWidget->setCaption("");
static_cast<MyGUI::TextBox*>(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<std::string>();
if (name == "StatName")
{
MYGUI_DEBUG_ASSERT( ! spellNameWidget, "widget already assigned");
spellNameWidget = (*iter)->castType<StaticText>();
}
}
}
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<MyGUI::TextBox*>(textWidget)->setCaption(spellLine);
}
else
textWidget->setCaption("");
static_cast<MyGUI::TextBox*>(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<std::string>();
if (name == "Text")
{
MYGUI_DEBUG_ASSERT( ! textWidget, "widget already assigned");
textWidget = (*iter)->castType<StaticText>();
}
else if (name == "Image")
{
MYGUI_DEBUG_ASSERT( ! imageWidget, "widget already assigned");
imageWidget = (*iter)->castType<StaticImage>();
}
}
}
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<MyGUI::TextBox*>(barTextWidget)->setCaption(out.str().c_str());
}
else
barTextWidget->setCaption("");
static_cast<MyGUI::TextBox*>(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<MyGUI::TextBox*>(textWidget)->setCaption(text);
}
MWDynamicStat::~MWDynamicStat()
{
shutdownWidgetSkin();
}
void MWDynamicStat::baseChangeWidgetSkin(ResourceSkin* _info)
{
shutdownWidgetSkin();
Base::baseChangeWidgetSkin(_info);
initialiseWidgetSkin(_info);
}
void MWDynamicStat::initialiseWidgetSkin(ResourceSkin* _info)
void MWDynamicStat::initialiseOverride()
{
for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
{
const std::string &name = *(*iter)->_getInternalData<std::string>();
if (name == "Text")
{
MYGUI_DEBUG_ASSERT( ! textWidget, "widget already assigned");
textWidget = (*iter)->castType<StaticText>();
}
else if (name == "Bar")
{
MYGUI_DEBUG_ASSERT( ! barWidget, "widget already assigned");
barWidget = (*iter)->castType<Progress>();
}
else if (name == "BarText")
{
MYGUI_DEBUG_ASSERT( ! barTextWidget, "widget already assigned");
barTextWidget = (*iter)->castType<StaticText>();
}
}
}
Base::initialiseOverride();
void MWDynamicStat::shutdownWidgetSkin()
{
assignWidget(textWidget, "Text");
assignWidget(barWidget, "Bar");
assignWidget(barTextWidget, "BarText");
}

@ -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<MWSkill*> EventHandle_SkillVoid;
typedef delegates::CMultiDelegate1<MWSkill*> 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<MWAttribute*> EventHandle_AttributeVoid;
typedef delegates::CMultiDelegate1<MWAttribute*> 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;

@ -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;

@ -13,7 +13,7 @@ namespace MWGui
WindowBase(const std::string& parLayout, WindowManager& parWindowManager);
// Events
typedef MyGUI::delegates::CDelegate1<WindowBase*> EventHandle_WindowBase;
typedef MyGUI::delegates::CMultiDelegate1<WindowBase*> EventHandle_WindowBase;
virtual void open();
void center();

@ -4,6 +4,7 @@
#include "review.hpp"
#include "dialogue.hpp"
#include "dialogue_history.hpp"
#include "map_window.hpp"
#include "stats_window.hpp"
#include "messagebox.hpp"
@ -22,31 +23,56 @@ 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<DialogeHistory>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<DialogueHistory>("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);
map = new MapWindow();
map = new MapWindow(*this);
stats = new StatsWindow(*this);
console = new Console(w,h, environment, extensions);
mJournal = new JournalWindow(*this);
@ -153,73 +179,60 @@ void WindowManager::updateVisible()
dialogueWindow->setVisible(false);
// Mouse is visible whenever we're not in game mode
gui->setVisiblePointer(isGuiMode());
// If in game mode, don't show anything.
if(mode == GM_Game) //Use a switch/case structure
{
return;
}
if(mode == GM_MainMenu)
{
// Enable the main menu
menu->setVisible(true);
return;
}
if(mode == GM_Console)
{
console->enable();
return;
}
//There must be a more elegant solution
if (mode == GM_Name || mode == GM_Race || mode == GM_Class || mode == GM_ClassPick || mode == GM_ClassCreate || mode == GM_Birth || mode == GM_ClassGenerate || mode == GM_Review)
{
mCharGen->spawnDialog(mode);
return;
}
if(mode == GM_Inventory)
{
// Ah, inventory mode. First, compute the effective set of
// windows to show. This is controlled both by what windows the
// user has opened/closed (the 'shown' variable) and by what
// windows we are allowed to show (the 'allowed' var.)
int eff = shown & allowed;
// Show the windows we want
map -> setVisible( (eff & GW_Map) != 0 );
stats -> setVisible( (eff & GW_Stats) != 0 );
return;
}
if (mode == GM_Dialogue)
{
dialogueWindow->open();
return;
}
if(mode == GM_InterMessageBox)
{
if(!mMessageBoxManager->isInteractiveMessageBox()) {
setGuiMode(GM_Game);
MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
switch(mode) {
case GM_Game:
// If in game mode, don't show anything.
break;
case GM_MainMenu:
menu->setVisible(true);
break;
case GM_Console:
console->enable();
break;
case GM_Name:
case GM_Race:
case GM_Class:
case GM_ClassPick:
case GM_ClassCreate:
case GM_Birth:
case GM_ClassGenerate:
case GM_Review:
mCharGen->spawnDialog(mode);
break;
case GM_Inventory:
{
// First, compute the effective set of windows to show.
// This is controlled both by what windows the
// user has opened/closed (the 'shown' variable) and by what
// windows we are allowed to show (the 'allowed' var.)
int eff = shown & allowed;
// Show the windows we want
map -> setVisible( (eff & GW_Map) != 0 );
stats -> setVisible( (eff & GW_Stats) != 0 );
break;
}
return;
}
if(mode == GM_Journal)
{
mJournal->setVisible(true);
mJournal->open();
return;
case GM_Dialogue:
dialogueWindow->open();
break;
case GM_InterMessageBox:
if(!mMessageBoxManager->isInteractiveMessageBox()) {
setGuiMode(GM_Game);
}
break;
case GM_Journal:
mJournal->setVisible(true);
mJournal->open();
break;
default:
// Unsupported mode, switch back to game
// Note: The call will eventually end up this method again but
// will stop at the check if mode is GM_Game.
setGuiMode(GM_Game);
break;
}
// Unsupported mode, switch back to game
// Note: The call will eventually end up this method again but
// will stop at the check if(mode == GM_Game) above.
setGuiMode(GM_Game);
}
void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int>& value)
@ -346,7 +359,6 @@ void WindowManager::updateSkillArea()
void WindowManager::removeDialog(OEngine::GUI::Layout*dialog)
{
std::cout << "dialogue a la poubelle";
assert(dialog);
if (!dialog)
return;
@ -400,3 +412,63 @@ 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);
}
void WindowManager::setHMSVisibility(bool visible)
{
hud->setBottomLeftVisibility(visible, hud->weapBox->getVisible(), hud->spellBox->getVisible());
}
void WindowManager::setMinimapVisibility(bool visible)
{
hud->setBottomRightVisibility(hud->effectBox->getVisible(), visible);
}
void WindowManager::toggleFogOfWar()
{
map->toggleFogOfWar();
hud->toggleFogOfWar();
}

@ -18,6 +18,7 @@
#include <openengine/ogre/renderer.hpp>
#include <openengine/gui/manager.hpp>
#include "../mwmechanics/stat.hpp"
#include "../mwworld/ptr.hpp"
#include "mode.hpp"
namespace MyGUI
@ -152,6 +153,19 @@ 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 toggleFogOfWar();
void setInteriorMapTexture(const int x, const int y);
///< set the index of the map texture that should be used (for interiors)
// sets the visibility of the hud health/magicka/stamina bars
void setHMSVisibility(bool visible);
// sets the visibility of the hud minimap
void setMinimapVisibility(bool visible);
template<typename T>
void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr.

@ -0,0 +1,33 @@
#include "window_pinnable_base.hpp"
#include "window_manager.hpp"
using namespace MWGui;
WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, WindowManager& parWindowManager)
: WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false)
{
MyGUI::WindowPtr t = static_cast<MyGUI::WindowPtr>(mMainWidget);
t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed);
}
void WindowPinnableBase::setVisible(bool b)
{
// Pinned windows can not be hidden
if (mPinned && !b)
return;
WindowBase::setVisible(b);
mVisible = b;
}
void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName)
{
if ("PinToggle" == eventName)
{
mPinned = !mPinned;
onPinToggled();
}
eventDone(this);
}

@ -0,0 +1,28 @@
#ifndef MWGUI_WINDOW_PINNABLE_BASE_H
#define MWGUI_WINDOW_PINNABLE_BASE_H
#include "window_base.hpp"
namespace MWGui
{
class WindowManager;
class WindowPinnableBase: public WindowBase
{
public:
WindowPinnableBase(const std::string& parLayout, WindowManager& parWindowManager);
void setVisible(bool b);
private:
void onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName);
protected:
virtual void onPinToggled() = 0;
bool mPinned;
bool mVisible;
};
}
#endif

@ -71,7 +71,7 @@ namespace MWInput
};
// Class that handles all input and key bindings for OpenMW
class InputImpl : public Ogre::FrameListener
class InputImpl
{
OEngine::Input::DispatcherPtr disp;
OEngine::Render::OgreRenderer &ogre;
@ -201,8 +201,6 @@ namespace MWInput
// Add the exit listener
ogre.getRoot()->addFrameListener(&exit);
// Add ourselves as a frame listener to catch movement keys
ogre.getRoot()->addFrameListener(this);
// Set up the mouse handler and tell it about the player camera
mouse = MouseLookEventPtr(new MouseLookEvent(player.getRenderer()->getCamera()));
@ -266,7 +264,7 @@ namespace MWInput
}
//NOTE: Used to check for movement keys
bool frameRenderingQueued (const Ogre::FrameEvent &evt)
void update ()
{
// Tell OIS to handle all input events
input.capture();
@ -280,7 +278,7 @@ namespace MWInput
windows.update();
// Disable movement in Gui mode
if (windows.isGuiMode()) return true;
if (windows.isGuiMode()) return;
// Configure player movement according to keyboard input. Actual movement will
// be done in the physics system.
@ -311,18 +309,11 @@ namespace MWInput
player.setForwardBackward (0);
if (poller.isDown(A_Jump))
{
player.setUpDown (1);
}
else if (poller.isDown(A_Crouch))
{
player.setUpDown (-1);
}
else
player.setUpDown (0);
return true;
}
// Switch between gui modes. Besides controlling the Gui windows
@ -374,4 +365,9 @@ namespace MWInput
{
impl->setGuiMode(mode);
}
void MWInputManager::update()
{
impl->update();
}
}

@ -48,6 +48,8 @@ namespace MWInput
OMW::Engine& engine);
~MWInputManager();
void update();
void setGuiMode(MWGui::GuiMode mode);
};
}

@ -0,0 +1,77 @@
#include "actors.hpp"
#include <typeinfo>
#include <components/esm/loadnpc.hpp>
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
namespace MWMechanics
{
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
{
}
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused)
{
if (!paused && ptr.getRefData().getHandle()!="player")
MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip (
MWWorld::Class::get (ptr).getNpcStats (ptr), mEnvironment);
}
Actors::Actors (MWWorld::Environment& environment) : mEnvironment (environment), mDuration (0) {}
void Actors::addActor (const MWWorld::Ptr& ptr)
{
mActors.insert (ptr);
}
void Actors::removeActor (const MWWorld::Ptr& ptr)
{
mActors.erase (ptr);
}
void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore)
{
std::set<MWWorld::Ptr>::iterator iter = mActors.begin();
while (iter!=mActors.end())
if (iter->getCell()==cellStore)
{
mActors.erase (iter++);
}
else
++iter;
}
void Actors::update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement, float duration,
bool paused)
{
mDuration += duration;
if (mDuration>=0.25)
{
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter)
{
updateActor (*iter, mDuration);
if (iter->getTypeName()==typeid (ESM::NPC).name())
updateNpc (*iter, mDuration, paused);
}
mDuration = 0;
}
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end();
++iter)
{
Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter);
if (vector!=Ogre::Vector3::ZERO)
movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector));
}
}
}

@ -0,0 +1,51 @@
#ifndef GAME_MWMECHANICS_ACTORS_H
#define GAME_MWMECHANICS_ACTORS_H
#include <set>
#include <vector>
#include <string>
#include "../mwworld/ptr.hpp"
namespace Ogre
{
class Vector3;
}
namespace MWWorld
{
class Environment;
}
namespace MWMechanics
{
class Actors
{
MWWorld::Environment& mEnvironment;
std::set<MWWorld::Ptr> mActors;
float mDuration;
void updateActor (const MWWorld::Ptr& ptr, float duration);
void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused);
public:
Actors (MWWorld::Environment& environment);
void addActor (const MWWorld::Ptr& ptr);
///< Register an actor for stats management
void removeActor (const MWWorld::Ptr& ptr);
///< Deregister an actor for stats management
void dropActors (const MWWorld::Ptr::CellStore *cellStore);
///< Deregister all actors in the given cell.
void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement,
float duration, bool paused);
///< Update actor stats and store desired velocity vectors in \a movement
};
}
#endif

@ -222,14 +222,14 @@ namespace MWMechanics
MechanicsManager::MechanicsManager (MWWorld::Environment& environment)
: mEnvironment (environment), mUpdatePlayer (true), mClassSelected (false),
mRaceSelected (false)
mRaceSelected (false), mActors (environment)
{
buildPlayer();
}
void MechanicsManager::addActor (const MWWorld::Ptr& ptr)
{
mActors.insert (ptr);
mActors.addActor (ptr);
}
void MechanicsManager::removeActor (const MWWorld::Ptr& ptr)
@ -237,7 +237,7 @@ namespace MWMechanics
if (ptr==mWatched)
mWatched = MWWorld::Ptr();
mActors.erase (ptr);
mActors.removeActor (ptr);
}
void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore)
@ -245,16 +245,7 @@ namespace MWMechanics
if (!mWatched.isEmpty() && mWatched.getCell()==cellStore)
mWatched = MWWorld::Ptr();
std::set<MWWorld::Ptr>::iterator iter = mActors.begin();
while (iter!=mActors.end())
if (iter->getCell()==cellStore)
{
//std::cout << "Erasing an actor";
mActors.erase (iter++);
}
else
++iter;
mActors.dropActors (cellStore);
}
void MechanicsManager::watchActor (const MWWorld::Ptr& ptr)
@ -262,7 +253,8 @@ namespace MWMechanics
mWatched = ptr;
}
void MechanicsManager::update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement)
void MechanicsManager::update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement,
float duration, bool paused)
{
if (!mWatched.isEmpty())
{
@ -345,14 +337,7 @@ namespace MWMechanics
mEnvironment.mWindowManager->configureSkills (majorSkills, minorSkills);
}
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end();
++iter)
{
Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter);
if (vector!=Ogre::Vector3::ZERO)
movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector));
}
mActors.update (movement, duration, paused);
}
void MechanicsManager::setPlayerName (const std::string& name)

@ -1,7 +1,6 @@
#ifndef GAME_MWMECHANICS_MECHANICSMANAGER_H
#define GAME_MWMECHANICS_MECHANICSMANAGER_H
#include <set>
#include <vector>
#include <string>
@ -9,6 +8,7 @@
#include "creaturestats.hpp"
#include "npcstats.hpp"
#include "actors.hpp"
namespace Ogre
{
@ -25,13 +25,13 @@ namespace MWMechanics
class MechanicsManager
{
MWWorld::Environment& mEnvironment;
std::set<MWWorld::Ptr> mActors;
MWWorld::Ptr mWatched;
CreatureStats mWatchedCreature;
NpcStats mWatchedNpc;
bool mUpdatePlayer;
bool mClassSelected;
bool mRaceSelected;
Actors mActors;
void buildPlayer();
///< build player according to stored class/race/birthsign information. Will
@ -60,8 +60,12 @@ namespace MWMechanics
///< On each update look for changes in a previously registered actor and update the
/// GUI accordingly.
void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement);
void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement, float duration,
bool paused);
///< Update actor stats and store desired velocity vectors in \a movement
///
/// \param paused In game type does not currently advance (this usually means some GUI
/// component is up).
void setPlayerName (const std::string& name);
///< Set player name.

@ -8,6 +8,15 @@ using namespace Ogre;
using namespace MWRender;
using namespace NifOgre;
Actors::~Actors(){
std::map<MWWorld::Ptr, Animation*>::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<MWWorld::Ptr, Animation*>(ptr,anim));
delete mAllActors[ptr];
mAllActors[ptr] = anim;
//mAllActors.push_back(&anim);*/
}

@ -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);

@ -4,7 +4,30 @@
namespace MWRender{
std::map<std::string, int> 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){
@ -103,6 +126,11 @@ namespace MWRender{
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){
shapeNumber = 0;
if (allshapes == NULL || creaturemodel == NULL || skel == NULL)
{
return;
}
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)

@ -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
#endif

@ -2,37 +2,283 @@
#include <assert.h>
#include "OgreRoot.h"
#include "OgreRenderWindow.h"
#include "OgreSceneManager.h"
#include "OgreViewport.h"
#include "OgreCamera.h"
#include "OgreTextureManager.h"
#include <OgreNode.h>
#include <OgreSceneManager.h>
#include <OgreMaterial.h>
#include <OgreMaterialManager.h>
#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone
#include "../mwworld/environment.hpp"
#include "../mwworld/ptr.hpp"
#include <components/esm/loadstat.hpp>
#include <components/esm/loadpgrd.hpp>
#include "player.hpp"
using namespace MWRender;
using namespace Ogre;
Debugging::Debugging(OEngine::Physic::PhysicEngine* engine){
eng = engine;
namespace MWRender
{
static const std::string PATHGRID_POINT_MATERIAL = "pathgridPointMaterial";
static const std::string PATHGRID_LINE_MATERIAL = "pathgridLineMaterial";
static const std::string DEBUGGING_GROUP = "debugging";
static const int POINT_MESH_BASE = 35;
void Debugging::createGridMaterials()
{
if (mGridMatsCreated) return;
if (MaterialManager::getSingleton().getByName(PATHGRID_LINE_MATERIAL, DEBUGGING_GROUP).isNull())
{
MaterialPtr lineMatPtr = MaterialManager::getSingleton().create(PATHGRID_LINE_MATERIAL, DEBUGGING_GROUP);
lineMatPtr->setReceiveShadows(false);
lineMatPtr->getTechnique(0)->setLightingEnabled(true);
lineMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0);
lineMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,1,0);
lineMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0);
}
if (MaterialManager::getSingleton().getByName(PATHGRID_POINT_MATERIAL, DEBUGGING_GROUP).isNull())
{
MaterialPtr pointMatPtr = MaterialManager::getSingleton().create(PATHGRID_POINT_MATERIAL, DEBUGGING_GROUP);
pointMatPtr->setReceiveShadows(false);
pointMatPtr->getTechnique(0)->setLightingEnabled(true);
pointMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,0,0,0);
pointMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,0,0);
pointMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,0,0);
}
mGridMatsCreated = true;
}
void Debugging::destroyGridMaterials()
{
if (mGridMatsCreated)
{
MaterialManager::getSingleton().remove(PATHGRID_POINT_MATERIAL);
MaterialManager::getSingleton().remove(PATHGRID_LINE_MATERIAL);
mGridMatsCreated = false;
}
}
ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid)
{
ManualObject *result = mSceneMgr->createManualObject();
result->begin(PATHGRID_LINE_MATERIAL, RenderOperation::OT_LINE_LIST);
for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid->edges.begin();
it != pathgrid->edges.end();
it++)
{
const ESM::Pathgrid::Edge &edge = *it;
const ESM::Pathgrid::Point &p1 = pathgrid->points[edge.v0], &p2 = pathgrid->points[edge.v1];
Vector3 direction = (Vector3(p2.x, p2.y, p2.z) - Vector3(p1.x, p1.y, p1.z));
Vector3 lineDisplacement = direction.crossProduct(Vector3::UNIT_Z).normalisedCopy();
lineDisplacement = lineDisplacement * POINT_MESH_BASE +
Vector3(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape
result->position(Vector3(p1.x, p1.y, p1.z) + lineDisplacement);
result->position(Vector3(p2.x, p2.y, p2.z) + lineDisplacement);
}
result->end();
return result;
}
ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid)
{
ManualObject *result = mSceneMgr->createManualObject();
const float height = POINT_MESH_BASE * sqrtf(2);
result->begin(PATHGRID_POINT_MATERIAL, RenderOperation::OT_TRIANGLE_STRIP);
bool first = true;
uint32 startIndex = 0;
for(ESM::Pathgrid::PointList::const_iterator it = pathgrid->points.begin();
it != pathgrid->points.end();
it++, startIndex += 6)
{
Vector3 pointPos(it->x, it->y, it->z);
if (!first)
{
// degenerate triangle from previous octahedron
result->index(startIndex - 4); // 2nd point of previous octahedron
result->index(startIndex); // start point of current octahedron
}
result->position(pointPos + Vector3(0, 0, height)); // 0
result->position(pointPos + Vector3(-POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 1
result->position(pointPos + Vector3(POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 2
result->position(pointPos + Vector3(POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 3
result->position(pointPos + Vector3(-POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 4
result->position(pointPos + Vector3(0, 0, -height)); // 5
result->index(startIndex + 0);
result->index(startIndex + 1);
result->index(startIndex + 2);
result->index(startIndex + 5);
result->index(startIndex + 3);
result->index(startIndex + 4);
// degenerates
result->index(startIndex + 4);
result->index(startIndex + 5);
result->index(startIndex + 5);
// end degenerates
result->index(startIndex + 1);
result->index(startIndex + 4);
result->index(startIndex + 0);
result->index(startIndex + 3);
result->index(startIndex + 2);
first = false;
}
result->end();
return result;
}
Debugging::Debugging(SceneNode *mwRoot, MWWorld::Environment &env, OEngine::Physic::PhysicEngine *engine) :
mMwRoot(mwRoot), mEnvironment(env), mEngine(engine),
mSceneMgr(mwRoot->getCreator()),
mPathgridEnabled(false),
mInteriorPathgridNode(NULL), mPathGridRoot(NULL),
mGridMatsCreated(false)
{
ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP);
}
Debugging::~Debugging()
{
if (mPathgridEnabled)
{
togglePathgrid();
}
ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP);
}
bool Debugging::toggleRenderMode (int mode){
switch (mode)
switch (mode)
{
case MWWorld::World::Render_CollisionDebug:
// TODO use a proper function instead of accessing the member variable
// directly.
eng->setDebugRenderingMode (!eng->isDebugCreated);
return eng->isDebugCreated;
return mEngine->toggleDebugRendering();
case MWWorld::World::Render_Pathgrid:
togglePathgrid();
return mPathgridEnabled;
}
return false;
}
void Debugging::cellAdded(MWWorld::Ptr::CellStore *store)
{
mActiveCells.push_back(store);
if (mPathgridEnabled)
enableCellPathgrid(store);
}
void Debugging::cellRemoved(MWWorld::Ptr::CellStore *store)
{
mActiveCells.erase(std::remove(mActiveCells.begin(), mActiveCells.end(), store), mActiveCells.end());
if (mPathgridEnabled)
disableCellPathgrid(store);
}
void Debugging::togglePathgrid()
{
mPathgridEnabled = !mPathgridEnabled;
if (mPathgridEnabled)
{
createGridMaterials();
// add path grid meshes to already loaded cells
mPathGridRoot = mMwRoot->createChildSceneNode();
for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); it++)
{
enableCellPathgrid(*it);
}
}
else
{
// remove path grid meshes from already loaded cells
for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); it++)
{
disableCellPathgrid(*it);
}
mPathGridRoot->removeAndDestroyAllChildren();
mSceneMgr->destroySceneNode(mPathGridRoot);
mPathGridRoot = NULL;
destroyGridMaterials();
}
}
void Debugging::enableCellPathgrid(MWWorld::Ptr::CellStore *store)
{
ESM::Pathgrid *pathgrid = mEnvironment.mWorld->getStore().pathgrids.search(*store->cell);
if (!pathgrid) return;
Vector3 cellPathGridPos(0, 0, 0);
if (store->cell->isExterior())
{
cellPathGridPos.x = store->cell->data.gridX * ESM::Land::REAL_SIZE;
cellPathGridPos.y = store->cell->data.gridY * ESM::Land::REAL_SIZE;
}
SceneNode *cellPathGrid = mPathGridRoot->createChildSceneNode(cellPathGridPos);
cellPathGrid->attachObject(createPathgridLines(pathgrid));
cellPathGrid->attachObject(createPathgridPoints(pathgrid));
if (store->cell->isExterior())
{
mExteriorPathgridNodes[std::make_pair(store->cell->data.gridX, store->cell->data.gridY)] = cellPathGrid;
}
else
{
assert(mInteriorPathgridNode == NULL);
mInteriorPathgridNode = cellPathGrid;
}
}
void Debugging::disableCellPathgrid(MWWorld::Ptr::CellStore *store)
{
if (store->cell->isExterior())
{
ExteriorPathgridNodes::iterator it =
mExteriorPathgridNodes.find(std::make_pair(store->cell->data.gridX, store->cell->data.gridY));
if (it != mExteriorPathgridNodes.end())
{
destroyCellPathgridNode(it->second);
mExteriorPathgridNodes.erase(it);
}
}
else
{
if (mInteriorPathgridNode)
{
destroyCellPathgridNode(mInteriorPathgridNode);
mInteriorPathgridNode = NULL;
}
}
}
void Debugging::destroyCellPathgridNode(SceneNode *node)
{
mPathGridRoot->removeChild(node);
destroyAttachedObjects(node);
mSceneMgr->destroySceneNode(node);
}
void Debugging::destroyAttachedObjects(SceneNode *node)
{
SceneNode::ObjectIterator objIt = node->getAttachedObjectIterator();
while (objIt.hasMoreElements())
{
MovableObject *mesh = static_cast<MovableObject *>(objIt.getNext());
mSceneMgr->destroyMovableObject(mesh);
}
}
}

@ -4,6 +4,7 @@
#include <utility>
#include <openengine/ogre/renderer.hpp>
#include <openengine/bullet/physic.hpp>
#include "../mwworld/ptr.hpp"
#include <vector>
#include <string>
@ -22,20 +23,58 @@ namespace Ogre
namespace MWWorld
{
class World;
class Environment;
}
namespace MWRender
{
class Player;
class Debugging{
OEngine::Physic::PhysicEngine* eng;
class Debugging
{
OEngine::Physic::PhysicEngine* mEngine;
Ogre::SceneManager *mSceneMgr;
MWWorld::Environment& mEnvironment;
// Path grid stuff
bool mPathgridEnabled;
public:
Debugging(OEngine::Physic::PhysicEngine* engine);
bool toggleRenderMode (int mode);
};
void togglePathgrid();
typedef std::vector<MWWorld::Ptr::CellStore *> CellList;
CellList mActiveCells;
Ogre::SceneNode *mMwRoot;
Ogre::SceneNode *mPathGridRoot;
typedef std::map<std::pair<int,int>, Ogre::SceneNode *> ExteriorPathgridNodes;
ExteriorPathgridNodes mExteriorPathgridNodes;
Ogre::SceneNode *mInteriorPathgridNode;
void enableCellPathgrid(MWWorld::Ptr::CellStore *store);
void disableCellPathgrid(MWWorld::Ptr::CellStore *store);
// utility
void destroyCellPathgridNode(Ogre::SceneNode *node);
void destroyAttachedObjects(Ogre::SceneNode *node);
// materials
bool mGridMatsCreated;
void createGridMaterials();
void destroyGridMaterials();
// path grid meshes
Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid);
Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid);
public:
Debugging(Ogre::SceneNode* mwRoot, MWWorld::Environment &env, OEngine::Physic::PhysicEngine *engine);
~Debugging();
bool toggleRenderMode (int mode);
void cellAdded(MWWorld::Ptr::CellStore* store);
void cellRemoved(MWWorld::Ptr::CellStore* store);
};
}

@ -0,0 +1,353 @@
#include "localmap.hpp"
#include "renderingmanager.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
#include "../mwgui/window_manager.hpp"
#include <OgreOverlayManager.h>
#include <OgreMaterialManager.h>
using namespace MWRender;
using namespace Ogre;
LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering, MWWorld::Environment* env) :
mInterior(false), mCellX(0), mCellY(0)
{
mRendering = rend;
mRenderingManager = rendering;
mEnvironment = env;
mCameraPosNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode();
mCameraRotNode = mCameraPosNode->createChildSceneNode();
mCameraNode = mCameraRotNode->createChildSceneNode();
mCellCamera = mRendering->getScene()->createCamera("CellCamera");
mCellCamera->setProjectionType(PT_ORTHOGRAPHIC);
// look down -y
const float sqrt0pt5 = 0.707106781;
mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0));
mCameraNode->attachObject(mCellCamera);
}
LocalMap::~LocalMap()
{
deleteBuffers();
}
const Ogre::Vector2 LocalMap::rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle)
{
return Vector2( Math::Cos(angle) * (p.x - c.x) - Math::Sin(angle) * (p.y - c.y) + c.x,
Math::Sin(angle) * (p.x - c.x) + Math::Cos(angle) * (p.y - c.y) + c.y);
}
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<uchar*>(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);
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; x<segsX; ++x)
{
for (int y=0; y<segsY; ++y)
{
/*saveTexture(
mInteriorName + "_" + coordStr(x,y) + "_fog",
mInteriorName + "_" + coordStr(x,y) + "_fog.png");*/
}
}
}
}
void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell)
{
mInterior = false;
mCameraRotNode->setOrientation(Quaternion::IDENTITY);
std::string name = "Cell_"+coordStr(cell->cell->data.gridX, cell->cell->data.gridY);
int x = cell->cell->data.gridX;
int y = cell->cell->data.gridY;
mCameraPosNode->setPosition(Vector3(0,0,0));
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(mBounds.getMaximum().y, mBounds.getMinimum().y);
const Vector2& north = mEnvironment->mWorld->getNorthVector(cell);
Radian angle(std::atan2(-north.x, -north.y));
mAngle = angle.valueRadians();
mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, Math::Sin(angle/2.f), 0));
// rotate the cell and merge the rotated corners to the bounding box
Vector2 _center(bounds.getCenter().x, bounds.getCenter().z);
Vector3 _c1 = bounds.getCorner(AxisAlignedBox::NEAR_LEFT_BOTTOM);
Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM);
Vector3 _c3 = bounds.getCorner(AxisAlignedBox::NEAR_RIGHT_BOTTOM);
Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM);
Vector2 c1(_c1.x, _c1.z);
Vector2 c2(_c2.x, _c2.z);
Vector2 c3(_c3.x, _c3.z);
Vector2 c4(_c4.x, _c4.z);
c1 = rotatePoint(c1, _center, mAngle);
c2 = rotatePoint(c2, _center, mAngle);
c3 = rotatePoint(c3, _center, mAngle);
c4 = rotatePoint(c4, _center, mAngle);
mBounds.merge(Vector3(c1.x, 0, c1.y));
mBounds.merge(Vector3(c2.x, 0, c2.y));
mBounds.merge(Vector3(c3.x, 0, c3.y));
mBounds.merge(Vector3(c4.x, 0, c4.y));
Vector2 center(mBounds.getCenter().x, mBounds.getCenter().z);
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z);
Vector2 length = max-min;
mCameraPosNode->setPosition(Vector3(center.x, 0, center.y));
// 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; x<segsX; ++x)
{
for (int y=0; y<segsY; ++y)
{
Vector2 start = min + Vector2(sSize*x,sSize*y);
Vector2 newcenter = start + 4096;
render(newcenter.x - center.x, newcenter.y - center.y, z.y, z.x, sSize, sSize,
cell->cell->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));
mRenderingManager->disableLights();
mCameraNode->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<uint32> buffer;
buffer.resize(sFogOfWarResolution*sFogOfWarResolution);
// initialize to (0, 0, 0, 1)
for (int p=0; p<sFogOfWarResolution*sFogOfWarResolution; ++p)
{
buffer[p] = (255 << 24);
}
memcpy(tex2->getBuffer()->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");
}
}
mRenderingManager->enableLights();
// re-enable fog
mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd);
}
void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation)
{
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;
Vector3 _pos(position.x, 0, position.z);
Vector2 pos(_pos.x, _pos.z);
if (mInterior)
{
pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle);
}
Vector3 playerdirection = -mCameraRotNode->convertWorldToLocalOrientation(orientation).zAxis();
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
if (!mInterior)
{
x = std::ceil(pos.x / sSize)-1;
y = std::ceil(-pos.y / sSize)-1;
mCellX = x;
mCellY = y;
}
else
{
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
{
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(playerdirection.x, -playerdirection.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<sFogOfWarResolution; ++texV)
{
for (int texU = 0; texU<sFogOfWarResolution; ++texU)
{
float sqrDist = Math::Sqr(texU - u*sFogOfWarResolution) + Math::Sqr(texV - v*sFogOfWarResolution);
uint32 clr = mBuffers[texName][i];
uint8 alpha = (clr >> 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();
}
}

@ -0,0 +1,109 @@
#ifndef _GAME_RENDER_LOCALMAP_H
#define _GAME_RENDER_LOCALMAP_H
#include "../mwworld/ptr.hpp"
#include <openengine/ogre/renderer.hpp>
namespace MWWorld
{
class Environment;
}
namespace MWRender
{
class RenderingManager;
///
/// \brief Local map rendering
///
class LocalMap
{
public:
LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering, 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 camera orientation (OGRE coordinates)
*/
void updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation);
/**
* 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;
MWRender::RenderingManager* mRenderingManager;
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;
Ogre::SceneNode* mCameraNode;
Ogre::SceneNode* mCameraPosNode;
Ogre::SceneNode* mCameraRotNode;
float mAngle;
const Ogre::Vector2 rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle);
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 <std::string, std::vector<Ogre::uint32> > mBuffers;
void deleteBuffers();
bool mInterior;
int mCellX, mCellY;
Ogre::AxisAlignedBox mBounds;
std::string mInteriorName;
};
}
#endif

@ -3,6 +3,7 @@
#include <OgreSceneNode.h>
#include <components/nifogre/ogre_nif_loader.hpp>
#include <components/settings/settings.hpp>
using namespace MWRender;
@ -90,33 +91,73 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
NifOgre::NIFLoader::load(mesh);
Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh);
if(!mIsStatic)
Ogre::Vector3 extents = ent->getBoundingBox().getSize();
extents *= insert->getScale();
float size = std::max(std::max(extents.x, extents.y), extents.z);
bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && Settings::Manager::getBool("limit small object distance", "Objects");
// do not fade out doors. that will cause holes and look stupid
if (ptr.getTypeName().find("Door") != std::string::npos)
small = false;
if (mBounds.find(ptr.getCell()) == mBounds.end())
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
Ogre::AxisAlignedBox bounds = ent->getBoundingBox();
bounds = Ogre::AxisAlignedBox(
insert->_getDerivedPosition() + bounds.getMinimum(),
insert->_getDerivedPosition() + bounds.getMaximum()
);
bounds.scale(insert->getScale());
mBounds[ptr.getCell()].merge(bounds);
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects"))
{
insert->attachObject(ent);
ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); /// \todo config value
}
else
{
Ogre::StaticGeometry* sg = 0;
if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
if (small)
{
uniqueID = uniqueID +1;
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
//Create the scenenode and put it in the map
mStaticGeometry[ptr.getCell()] = sg;
// This specifies the size of a single batch region.
// If it is set too high:
// - there will be problems choosing the correct lights
// - the culling will be more inefficient
// If it is set too low:
// - there will be too many batches.
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
{
uniqueID = uniqueID +1;
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
mStaticGeometrySmall[ptr.getCell()] = sg;
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); /// \todo config value
}
else
sg = mStaticGeometrySmall[ptr.getCell()];
}
else
{
sg = mStaticGeometry[ptr.getCell()];
if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
{
uniqueID = uniqueID +1;
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
mStaticGeometry[ptr.getCell()] = sg;
}
else
sg = mStaticGeometry[ptr.getCell()];
}
// This specifies the size of a single batch region.
// If it is set too high:
// - there will be problems choosing the correct lights
// - the culling will be more inefficient
// If it is set too low:
// - there will be too many batches.
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
mRenderer.getScene()->destroyEntity(ent);
@ -129,6 +170,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f
assert(insert);
Ogre::Light *light = mRenderer.getScene()->createLight();
light->setDiffuseColour (r, g, b);
mLights.push_back(light->getName());
float cval=0.0f, lval=0.0f, qval=0.0f;
@ -204,6 +246,16 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store)
mRenderer.getScene()->destroyStaticGeometry (sg);
sg = 0;
}
if(mStaticGeometrySmall.find(store) != mStaticGeometrySmall.end())
{
Ogre::StaticGeometry* sg = mStaticGeometrySmall[store];
mStaticGeometrySmall.erase(store);
mRenderer.getScene()->destroyStaticGeometry (sg);
sg = 0;
}
if(mBounds.find(store) != mBounds.end())
mBounds.erase(store);
}
void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
@ -213,4 +265,45 @@ void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
Ogre::StaticGeometry* sg = mStaticGeometry[&cell];
sg->build();
}
if(mStaticGeometrySmall.find(&cell) != mStaticGeometrySmall.end())
{
Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell];
sg->build();
}
}
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
{
return mBounds[cell];
}
void Objects::enableLights()
{
std::vector<std::string>::iterator it = mLights.begin();
while (it != mLights.end())
{
if (mMwRoot->getCreator()->hasLight(*it))
{
mMwRoot->getCreator()->getLight(*it)->setVisible(true);
++it;
}
else
it = mLights.erase(it);
}
}
void Objects::disableLights()
{
std::vector<std::string>::iterator it = mLights.begin();
while (it != mLights.end())
{
if (mMwRoot->getCreator()->hasLight(*it))
{
mMwRoot->getCreator()->getLight(*it)->setVisible(false);
++it;
}
else
it = mLights.erase(it);
}
}

@ -14,6 +14,9 @@ class Objects{
OEngine::Render::OgreRenderer &mRenderer;
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds;
std::vector<std::string> mLights;
Ogre::SceneNode* mMwRoot;
bool mIsStatic;
static int uniqueID;
@ -42,6 +45,12 @@ 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);
void enableLights();
void disableLights();
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?

@ -0,0 +1,303 @@
#include "occlusionquery.hpp"
#include <OgreRenderSystem.h>
#include <OgreRoot.h>
#include <OgreBillboardSet.h>
#include <OgreHardwareOcclusionQuery.h>
#include <OgreEntity.h>
#include <OgreSubEntity.h>
#include <OgreMaterialManager.h>
using namespace MWRender;
using namespace Ogre;
OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) :
mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0),
mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false),
mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false),
mBBNode(0)
{
mRendering = renderer;
mSunNode = sunNode;
try {
RenderSystem* renderSystem = Root::getSingleton().getRenderSystem();
mSunTotalAreaQuery = renderSystem->createHardwareOcclusionQuery();
mSunVisibleAreaQuery = renderSystem->createHardwareOcclusionQuery();
mSingleObjectQuery = renderSystem->createHardwareOcclusionQuery();
mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0) && (mSingleObjectQuery != 0);
}
catch (Ogre::Exception e)
{
mSupported = false;
}
if (!mSupported)
{
std::cout << "Hardware occlusion queries not supported." << std::endl;
return;
}
// This means that everything up to RENDER_QUEUE_MAIN can occlude the objects that are tested
const int queue = RENDER_QUEUE_MAIN+1;
MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting");
MaterialPtr matQueryArea = matBase->clone("QueryTotalPixels");
matQueryArea->setDepthWriteEnabled(false);
matQueryArea->setColourWriteEnabled(false);
matQueryArea->setDepthCheckEnabled(false); // Not occluded by objects
MaterialPtr matQueryVisible = matBase->clone("QueryVisiblePixels");
matQueryVisible->setDepthWriteEnabled(false);
matQueryVisible->setColourWriteEnabled(false); // Uncomment this to visualize the occlusion query
matQueryVisible->setDepthCheckEnabled(true); // Occluded by objects
matQueryVisible->setCullingMode(CULL_NONE);
matQueryVisible->setManualCullingMode(MANUAL_CULL_NONE);
if (sunNode)
mBBNode = mSunNode->getParentSceneNode()->createChildSceneNode();
mObjectNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode();
mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode();
mBBQueryTotal = mRendering->getScene()->createBillboardSet(1);
mBBQueryTotal->setDefaultDimensions(150, 150);
mBBQueryTotal->createBillboard(Vector3::ZERO);
mBBQueryTotal->setMaterialName("QueryTotalPixels");
mBBQueryTotal->setRenderQueueGroup(queue+1);
mBBNodeReal->attachObject(mBBQueryTotal);
mBBQueryVisible = mRendering->getScene()->createBillboardSet(1);
mBBQueryVisible->setDefaultDimensions(150, 150);
mBBQueryVisible->createBillboard(Vector3::ZERO);
mBBQueryVisible->setMaterialName("QueryVisiblePixels");
mBBQueryVisible->setRenderQueueGroup(queue+1);
mBBNodeReal->attachObject(mBBQueryVisible);
mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1);
/// \todo ideally this should occupy exactly 1 pixel on the screen
mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003);
mBBQuerySingleObject->createBillboard(Vector3::ZERO);
mBBQuerySingleObject->setMaterialName("QueryVisiblePixels");
mBBQuerySingleObject->setRenderQueueGroup(queue);
mObjectNode->attachObject(mBBQuerySingleObject);
mRendering->getScene()->addRenderObjectListener(this);
mRendering->getScene()->addRenderQueueListener(this);
mDoQuery = true;
}
OcclusionQuery::~OcclusionQuery()
{
RenderSystem* renderSystem = Root::getSingleton().getRenderSystem();
if (mSunTotalAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery);
if (mSunVisibleAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery);
if (mSingleObjectQuery) renderSystem->destroyHardwareOcclusionQuery(mSingleObjectQuery);
}
bool OcclusionQuery::supported()
{
return mSupported;
}
void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source,
const LightList* pLightList, bool suppressRenderStateChanges)
{
// The following code activates and deactivates the occlusion queries
// so that the queries only include the rendering of their intended targets
// Close the last occlusion query
// Each occlusion query should only last a single rendering
if (mActiveQuery != NULL)
{
mActiveQuery->endOcclusionQuery();
mActiveQuery = NULL;
}
// Open a new occlusion query
if (mDoQuery == true)
{
if (rend == mBBQueryTotal)
{
mActiveQuery = mSunTotalAreaQuery;
mWasVisible = true;
}
else if (rend == mBBQueryVisible)
{
mActiveQuery = mSunVisibleAreaQuery;
}
}
if (mDoQuery == true && rend == mBBQuerySingleObject)
{
mQuerySingleObjectStarted = true;
mQuerySingleObjectRequested = false;
mActiveQuery = mSingleObjectQuery;
mObjectWasVisible = true;
}
if (mActiveQuery != NULL)
mActiveQuery->beginOcclusionQuery();
}
void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation)
{
if (mActiveQuery != NULL)
{
mActiveQuery->endOcclusionQuery();
mActiveQuery = NULL;
}
/**
* for every beginOcclusionQuery(), we want a respective pullOcclusionQuery() and vice versa
* this also means that results can be wrong at other places if we pull, but beginOcclusionQuery() was never called
* this can happen for example if the object that is tested is outside of the view frustum
* to prevent this, check if the queries have been performed after everything has been rendered and if not, start them manually
*/
if (queueGroupId == RENDER_QUEUE_SKIES_LATE)
{
if (mWasVisible == false && mDoQuery)
{
mSunTotalAreaQuery->beginOcclusionQuery();
mSunTotalAreaQuery->endOcclusionQuery();
mSunVisibleAreaQuery->beginOcclusionQuery();
mSunVisibleAreaQuery->endOcclusionQuery();
}
if (mObjectWasVisible == false && mDoQuery)
{
mSingleObjectQuery->beginOcclusionQuery();
mSingleObjectQuery->endOcclusionQuery();
mQuerySingleObjectStarted = true;
mQuerySingleObjectRequested = false;
}
}
}
void OcclusionQuery::update(float duration)
{
if (!mSupported) return;
mWasVisible = false;
mObjectWasVisible = false;
// Adjust the position of the sun billboards according to camera viewing distance
// we need to do this to make sure that _everything_ can occlude the sun
float dist = mRendering->getCamera()->getFarClipDistance();
if (dist==0) dist = 10000000;
dist -= 1000; // bias
dist /= 1000.f;
if (mBBNode)
{
mBBNode->setPosition(mSunNode->getPosition() * dist);
mBBNode->setScale(dist, dist, dist);
mBBNodeReal->setPosition(mBBNode->_getDerivedPosition());
mBBNodeReal->setScale(mBBNode->getScale());
}
// Stop occlusion queries until we get their information
// (may not happen on the same frame they are requested in)
mDoQuery = false;
if (!mSunTotalAreaQuery->isStillOutstanding()
&& !mSunVisibleAreaQuery->isStillOutstanding()
&& !mSingleObjectQuery->isStillOutstanding())
{
unsigned int totalPixels;
unsigned int visiblePixels;
mSunTotalAreaQuery->pullOcclusionQuery(&totalPixels);
mSunVisibleAreaQuery->pullOcclusionQuery(&visiblePixels);
if (totalPixels == 0)
{
// probably outside of the view frustum
mSunVisibility = 0;
}
else
{
mSunVisibility = float(visiblePixels) / float(totalPixels);
if (mSunVisibility > 1) mSunVisibility = 1;
}
unsigned int result;
mSingleObjectQuery->pullOcclusionQuery(&result);
mTestResult = (result != 0);
mQuerySingleObjectStarted = false;
mQuerySingleObjectRequested = false;
mDoQuery = true;
}
}
void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNode* object)
{
assert( !occlusionTestPending()
&& "Occlusion test still pending");
mBBQuerySingleObject->setVisible(true);
mObjectNode->setPosition(position);
// scale proportional to camera distance, in order to always give the billboard the same size in screen-space
mObjectNode->setScale( Vector3(1,1,1)*(position - mRendering->getCamera()->getRealPosition()).length() );
mQuerySingleObjectRequested = true;
}
bool OcclusionQuery::occlusionTestPending()
{
return (mQuerySingleObjectRequested || mQuerySingleObjectStarted);
}
void OcclusionQuery::setSunNode(Ogre::SceneNode* node)
{
mSunNode = node;
if (!mBBNode)
mBBNode = node->getParentSceneNode()->createChildSceneNode();
}
bool OcclusionQuery::getTestResult()
{
assert( !occlusionTestPending()
&& "Occlusion test still pending");
return mTestResult;
}
bool OcclusionQuery::isPotentialOccluder(Ogre::SceneNode* node)
{
bool result = false;
for (unsigned int i=0; i < node->numAttachedObjects(); ++i)
{
MovableObject* ob = node->getAttachedObject(i);
std::string type = ob->getMovableType();
if (type == "Entity")
{
Entity* ent = static_cast<Entity*>(ob);
for (unsigned int j=0; j < ent->getNumSubEntities(); ++j)
{
// if any sub entity has a material with depth write off,
// consider the object as not an occluder
MaterialPtr mat = ent->getSubEntity(j)->getMaterial();
Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (techIt.hasMoreElements())
{
Technique* tech = techIt.getNext();
Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements())
{
Pass* pass = passIt.getNext();
if (pass->getDepthWriteEnabled() == false)
return false;
else
result = true;
}
}
}
}
}
return result;
}

@ -0,0 +1,105 @@
#ifndef _GAME_OCCLUSION_QUERY_H
#define _GAME_OCCLUSION_QUERY_H
#include <OgreRenderObjectListener.h>
#include <OgreRenderQueueListener.h>
namespace Ogre
{
class HardwareOcclusionQuery;
class Entity;
class SceneNode;
}
#include <openengine/ogre/renderer.hpp>
namespace MWRender
{
///
/// \brief Implements hardware occlusion queries on the GPU
///
class OcclusionQuery : public Ogre::RenderObjectListener, public Ogre::RenderQueueListener
{
public:
OcclusionQuery(OEngine::Render::OgreRenderer*, Ogre::SceneNode* sunNode);
~OcclusionQuery();
/**
* @return true if occlusion queries are supported on the user's hardware
*/
bool supported();
/**
* per-frame update
*/
void update(float duration);
/**
* request occlusion test for a billboard at the given position, omitting an entity
* @param position of the billboard in ogre coordinates
* @param object to exclude from the occluders
*/
void occlusionTest(const Ogre::Vector3& position, Ogre::SceneNode* object);
/**
* @return true if a request is still outstanding
*/
bool occlusionTestPending();
/**
* Checks if the objects held by this scenenode
* can be considered as potential occluders
* (which might not be the case when transparency is involved)
* @param Scene node
*/
bool isPotentialOccluder(Ogre::SceneNode* node);
/**
* @return true if the object tested in the last request was occluded
*/
bool getTestResult();
float getSunVisibility() const {return mSunVisibility;};
void setSunNode(Ogre::SceneNode* node);
private:
Ogre::HardwareOcclusionQuery* mSunTotalAreaQuery;
Ogre::HardwareOcclusionQuery* mSunVisibleAreaQuery;
Ogre::HardwareOcclusionQuery* mSingleObjectQuery;
Ogre::HardwareOcclusionQuery* mActiveQuery;
Ogre::BillboardSet* mBBQueryVisible;
Ogre::BillboardSet* mBBQueryTotal;
Ogre::BillboardSet* mBBQuerySingleObject;
Ogre::SceneNode* mSunNode;
Ogre::SceneNode* mBBNode;
Ogre::SceneNode* mBBNodeReal;
float mSunVisibility;
Ogre::SceneNode* mObjectNode;
bool mWasVisible;
bool mObjectWasVisible;
bool mTestResult;
bool mSupported;
bool mDoQuery;
bool mDoQuery2;
bool mQuerySingleObjectRequested;
bool mQuerySingleObjectStarted;
OEngine::Render::OgreRenderer* mRendering;
protected:
virtual void notifyRenderSingleObject(Ogre::Renderable* rend, const Ogre::Pass* pass, const Ogre::AutoParamDataSource* source,
const Ogre::LightList* pLightList, bool suppressRenderStateChanges);
virtual void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation);
};
}
#endif

@ -12,6 +12,7 @@
#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone
#include "../mwworld/ptr.hpp"
#include <components/esm/loadstat.hpp>
#include <components/settings/settings.hpp>
using namespace MWRender;
@ -20,12 +21,28 @@ using namespace Ogre;
namespace MWRender {
RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment)
:mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mDebugging(engine)
:mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0)
{
mRendering.createScene("PlayerCam", 55, 5);
mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5);
mTerrainManager = new TerrainManager(mRendering.getScene(),
environment);
//The fog type must be set before any terrain objects are created as if the
//fog type is set to FOG_NONE then the initially created terrain won't have any fog
configureFog(1, ColourValue(1,1,1));
// Set default mipmap level (NB some APIs ignore this)
TextureManager::getSingleton().setDefaultNumMipmaps(5);
TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General"));
// Set default texture filtering options
TextureFilterOptions tfo;
std::string filter = Settings::Manager::getString("texture filtering", "General");
if (filter == "anisotropic") tfo = TFO_ANISOTROPIC;
else if (filter == "trilinear") tfo = TFO_TRILINEAR;
else /* if (filter == "bilinear") */ tfo = TFO_BILINEAR;
MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
MaterialManager::getSingleton().setDefaultAnisotropy(Settings::Manager::getInt("anisotropy", "General"));
// Load resources
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
@ -40,21 +57,25 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
mMwRoot->pitch(Degree(-90));
mObjects.setMwRoot(mMwRoot);
mActors.setMwRoot(mMwRoot);
//used to obtain ingame information of ogre objects (which are faced or selected)
mRaySceneQuery = mRendering.getScene()->createRayQuery(Ray());
Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player");
playerNode->pitch(Degree(90));
Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode();
Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode();
cameraPitchNode->attachObject(mRendering.getCamera());
//mSkyManager = 0;
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment);
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
mWater = 0;
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
mSun = 0;
mDebugging = new Debugging(mMwRoot, environment, engine);
mLocalMap = new MWRender::LocalMap(&mRendering, this, &environment);
}
RenderingManager::~RenderingManager ()
@ -62,6 +83,10 @@ RenderingManager::~RenderingManager ()
//TODO: destroy mSun?
delete mPlayer;
delete mSkyManager;
delete mDebugging;
delete mTerrainManager;
delete mLocalMap;
delete mOcclusionQuery;
}
MWRender::SkyManager* RenderingManager::getSkyManager()
@ -85,14 +110,35 @@ OEngine::Render::Fader* RenderingManager::getFader()
return mRendering.getFader();
}
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store){
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store)
{
mObjects.removeCell(store);
mActors.removeCell(store);
mDebugging->cellRemoved(store);
if (store->cell->isExterior())
mTerrainManager->cellRemoved(store);
}
void RenderingManager::removeWater ()
{
if(mWater){
delete mWater;
mWater = 0;
}
}
void RenderingManager::toggleWater()
{
if (mWater)
mWater->toggle();
}
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
{
mObjects.buildStaticGeometry (*store);
mDebugging->cellAdded(store);
if (store->cell->isExterior())
mTerrainManager->cellAdded(store);
}
void RenderingManager::addObject (const MWWorld::Ptr& ptr){
@ -133,16 +179,45 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve
void RenderingManager::update (float duration){
mActors.update (duration);
mOcclusionQuery->update(duration);
mSkyManager->update(duration);
mSkyManager->setGlare(mOcclusionQuery->getSunVisibility());
mRendering.update(duration);
mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealOrientation() );
checkUnderwater();
}
void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){
if(store->cell->data.flags & store->cell->HasWater){
if(mWater == 0)
mWater = new MWRender::Water(mRendering.getCamera(), store->cell);
else
mWater->changeCell(store->cell);
//else
}
else
removeWater();
}
void RenderingManager::setWaterHeight(const float height)
{
if (mWater)
mWater->setHeight(height);
}
void RenderingManager::skyEnable ()
{
if(mSkyManager)
mSkyManager->enable();
mOcclusionQuery->setSunNode(mSkyManager->getSunNode());
}
void RenderingManager::skyDisable ()
@ -166,7 +241,7 @@ void RenderingManager::skySetDate (int day, int month)
int RenderingManager::skyGetMasserPhase() const
{
return mSkyManager->getMasserPhase();
}
@ -182,8 +257,8 @@ void RenderingManager::skySetMoonColour (bool red){
bool RenderingManager::toggleRenderMode(int mode)
{
if (mode == MWWorld::World::Render_CollisionDebug)
return mDebugging.toggleRenderMode(mode);
if (mode != MWWorld::World::Render_Wireframe)
return mDebugging->toggleRenderMode(mode);
else // if (mode == MWWorld::World::Render_Wireframe)
{
if (mRendering.getCamera()->getPolygonMode() == PM_SOLID)
@ -208,19 +283,15 @@ void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
}
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
{
/// \todo make the viewing distance and fog start/end configurable
{
float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance");
// right now we load 3x3 cells, so the maximum viewing distance we
// can allow (to prevent objects suddenly popping up) equals:
// 8192 * 0.69
// ^ cell size ^ minimum density value used (clear weather)
float low = 5652.48 / density / 2.f;
float high = 5652.48 / density;
float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance");
float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance");
mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high);
mRendering.getCamera()->setFarClipDistance ( high );
mRendering.getCamera()->setFarClipDistance ( max / density );
mRendering.getViewport()->setBackgroundColour (colour);
}
@ -231,17 +302,17 @@ void RenderingManager::setAmbientMode()
{
case 0:
mRendering.getScene()->setAmbientLight(mAmbientColor);
setAmbientColour(mAmbientColor);
break;
case 1:
mRendering.getScene()->setAmbientLight(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1));
setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1));
break;
case 2:
mRendering.getScene()->setAmbientLight(ColourValue(1,1,1));
setAmbientColour(ColourValue(1,1,1));
break;
}
}
@ -281,6 +352,11 @@ void RenderingManager::toggleLight()
setAmbientMode();
}
void RenderingManager::checkUnderwater(){
if(mWater){
mWater->checkUnderwater( mRendering.getCamera()->getRealPosition().y );
}
}
void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
int mode, int number)
@ -296,11 +372,13 @@ void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr)
void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
{
mSun->setDiffuseColour(colour);
mTerrainManager->setDiffuse(colour);
}
void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
{
mRendering.getScene()->setAmbientLight(colour);
mTerrainManager->setAmbient(colour);
}
void RenderingManager::sunEnable()
@ -315,10 +393,10 @@ void RenderingManager::sunDisable()
void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
{
// direction * -1 (because 'direction' is camera to sun vector and not sun to camera),
// direction * -1 (because 'direction' is camera to sun vector and not sun to camera),
// then convert from MW to ogre coordinates (swap y,z and make y negative)
if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y));
mSkyManager->setSunDirection(direction);
}
@ -327,4 +405,27 @@ 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);
}
void RenderingManager::disableLights()
{
mObjects.disableLights();
}
void RenderingManager::enableLights()
{
mObjects.enableLights();
}
} // namespace

@ -3,6 +3,7 @@
#include "sky.hpp"
#include "terrain.hpp"
#include "debugging.hpp"
#include "../mwworld/class.hpp"
@ -24,6 +25,9 @@
#include "objects.hpp"
#include "actors.hpp"
#include "player.hpp"
#include "water.hpp"
#include "localmap.hpp"
#include "occlusionquery.hpp"
namespace Ogre
{
@ -58,6 +62,8 @@ class RenderingManager: private RenderingInterface {
RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment);
virtual ~RenderingManager();
virtual MWRender::Player& getPlayer(); /// \todo move this to private again as soon as
/// MWWorld::Player has been rewritten to not need access
/// to internal details of the rendering system anymore
@ -66,7 +72,7 @@ class RenderingManager: private RenderingInterface {
void toggleLight();
bool toggleRenderMode(int mode);
OEngine::Render::Fader* getFader();
void removeCell (MWWorld::Ptr::CellStore *store);
@ -74,6 +80,12 @@ class RenderingManager: private RenderingInterface {
/// \todo this function should be removed later. Instead the rendering subsystems should track
/// when rebatching is needed and update automatically at the end of each frame.
void cellAdded (MWWorld::Ptr::CellStore *store);
void waterAdded(MWWorld::Ptr::CellStore *store);
void removeWater();
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);
@ -82,17 +94,27 @@ class RenderingManager: private RenderingInterface {
void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale);
void rotateObject (const MWWorld::Ptr& ptr, const::Ogre::Quaternion& orientation);
void checkUnderwater();
void setWaterHeight(const float height);
void toggleWater();
/// \param store Cell the object was in previously (\a ptr has already been updated to the new cell).
void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::Ptr::CellStore *store);
void update (float duration);
void setAmbientColour(const Ogre::ColourValue& colour);
void setSunColour(const Ogre::ColourValue& colour);
void setSunDirection(const Ogre::Vector3& direction);
void sunEnable();
void sunDisable();
void disableLights();
void enableLights();
bool occlusionQuerySupported() { return mOcclusionQuery->supported(); };
OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; };
void setGlare(bool glare);
void skyEnable ();
void skyDisable ();
@ -102,13 +124,16 @@ class RenderingManager: private RenderingInterface {
int skyGetSecundaPhase() const;
void skySetMoonColour (bool red);
void configureAmbient(ESMS::CellStore<MWWorld::RefData> &mCell);
void requestMap (MWWorld::Ptr::CellStore* cell);
///< request the local map for a cell
/// configure fog according to cell
void configureFog(ESMS::CellStore<MWWorld::RefData> &mCell);
/// configure fog manually
void configureFog(const float density, const Ogre::ColourValue& colour);
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
int number = 1);
///< Run animation for a MW-reference. Calls to this function for references that are currently not
@ -124,9 +149,15 @@ class RenderingManager: private RenderingInterface {
private:
void setAmbientMode();
SkyManager* mSkyManager;
OcclusionQuery* mOcclusionQuery;
TerrainManager* mTerrainManager;
MWRender::Water *mWater;
OEngine::Render::OgreRenderer &mRendering;
MWRender::Objects mObjects;
@ -142,12 +173,14 @@ class RenderingManager: private RenderingInterface {
/// that the OGRE coordinate system matches that used internally in
/// Morrowind.
Ogre::SceneNode *mMwRoot;
Ogre::RaySceneQuery *mRaySceneQuery;
OEngine::Physic::PhysicEngine* mPhysicsEngine;
MWRender::Player *mPlayer;
MWRender::Debugging mDebugging;
MWRender::Debugging *mDebugging;
MWRender::LocalMap* mLocalMap;
};
}

@ -12,6 +12,7 @@
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
#include "occlusionquery.hpp"
using namespace MWRender;
using namespace Ogre;
@ -30,7 +31,7 @@ BillboardObject::BillboardObject()
void BillboardObject::setVisible(const bool visible)
{
mNode->setVisible(visible);
mBBSet->setVisible(visible);
}
void BillboardObject::setSize(const float size)
@ -88,7 +89,7 @@ void BillboardObject::init(const String& textureName,
/// \todo These billboards are not 100% correct, might want to revisit them later
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
mBBSet->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+2);
mBBSet->setRenderQueueGroup(RENDER_QUEUE_MAIN+2);
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
mBBSet->setCommonDirection( -position.normalisedCopy() );
mNode = rootNode->createChildSceneNode();
@ -254,7 +255,7 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType)
// Get a pointer to the vertex colour
ves_diffuse->baseVertexPointerToElement( pData, &currentVertex );
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,16 +293,49 @@ 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)
, mGlare(0.0f)
, mEnabled(true)
, mSunEnabled(true)
, mMasserEnabled(true)
, mSecundaEnabled(true)
, mCreated(false)
{
mEnvironment = env;
mViewport = pCamera->getViewport();
mSceneMgr = pMwRoot->getCreator();
mRootNode = pCamera->getParentSceneNode()->createChildSceneNode();
mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates
mRootNode->setInheritOrientation(false);
}
void SkyManager::create()
{
/// \todo preload all the textures and meshes that are used for sky rendering
// Create overlay used for thunderstorm
@ -446,6 +480,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");
@ -501,7 +536,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
" uniform float4 emissive \n"
") \n"
"{ \n"
" uv += float2(1,0) * time * speed * 0.003; \n" // Scroll in x direction
" uv += float2(0,1) * time * speed * 0.003; \n" // Scroll in y direction
" float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n"
" oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n"
"}";
@ -530,6 +565,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("");
mCreated = true;
}
SkyManager::~SkyManager()
@ -542,11 +579,13 @@ SkyManager::~SkyManager()
int SkyManager::getMasserPhase() const
{
if (!mCreated) return 0;
return mMasser->getPhaseInt();
}
int SkyManager::getSecundaPhase() const
{
if (!mCreated) return 0;
return mSecunda->getPhaseInt();
}
@ -561,10 +600,23 @@ void SkyManager::update(float duration)
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
// increase the strength of the sun glare effect depending
// on how directly the player is looking at the sun
if (mSunEnabled)
{
// take 1/5 sec for fading the glare effect from invisible to full
if (mGlareFade > mGlare)
{
mGlareFade -= duration*5;
if (mGlareFade < mGlare) mGlareFade = mGlare;
}
else if (mGlareFade < mGlare)
{
mGlareFade += duration*5;
if (mGlareFade > mGlare) mGlareFade = mGlare;
}
// increase the strength of the sun glare effect depending
// on how directly the player is looking at the sun
Vector3 sun = mSunGlare->getPosition();
sun = Vector3(sun.x, sun.z, -sun.y);
Vector3 cam = mViewport->getCamera()->getRealDirection();
@ -572,21 +624,10 @@ void SkyManager::update(float duration)
float val = 1- (angle.valueDegrees() / 180.f);
val = (val*val*val*val)*2;
if (mGlareEnabled)
{
mGlareFade += duration*3;
if (mGlareFade > 1) mGlareFade = 1;
}
else
{
mGlareFade -= duration*3;
if (mGlareFade < 0.3) mGlareFade = 0;
}
mSunGlare->setSize(val * (mGlareFade));
mSunGlare->setSize(val * mGlareFade);
}
mSunGlare->setVisible(mGlareFade>0 && mSunEnabled);
mSunGlare->setVisible(mSunEnabled);
mSun->setVisible(mSunEnabled);
mMasser->setVisible(mMasserEnabled);
mSecunda->setVisible(mSecundaEnabled);
@ -597,6 +638,9 @@ void SkyManager::update(float duration)
void SkyManager::enable()
{
if (!mCreated)
create();
mRootNode->setVisible(true);
mEnabled = true;
}
@ -620,6 +664,7 @@ void SkyManager::setCloudsOpacity(float opacity)
void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
{
if (!mCreated) return;
if (mClouds != weather.mCloudTexture)
{
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture);
@ -688,19 +733,20 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
else
strength = 1.f;
mSunGlare->setVisibility(weather.mGlareView * strength);
mSun->setVisibility(strength);
mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength);
mSun->setVisibility(mGlareFade >= 0.5 ? weather.mGlareView * mGlareFade * strength : 0);
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
}
void SkyManager::setGlare(bool glare)
void SkyManager::setGlare(const float glare)
{
mGlareEnabled = glare;
mGlare = glare;
}
Vector3 SkyManager::getRealSunPos()
{
if (!mCreated) return Vector3(0,0,0);
return mSun->getNode()->_getDerivedPosition();
}
@ -716,17 +762,20 @@ void SkyManager::sunDisable()
void SkyManager::setSunDirection(const Vector3& direction)
{
if (!mCreated) return;
mSun->setPosition(direction);
mSunGlare->setPosition(direction);
}
void SkyManager::setMasserDirection(const Vector3& direction)
{
if (!mCreated) return;
mMasser->setPosition(direction);
}
void SkyManager::setSecundaDirection(const Vector3& direction)
{
if (!mCreated) return;
mSecunda->setPosition(direction);
}
@ -752,6 +801,7 @@ void SkyManager::secundaDisable()
void SkyManager::setThunder(const float factor)
{
if (!mCreated) return;
if (factor > 0.f)
{
mThunderOverlay->show();
@ -781,3 +831,9 @@ void SkyManager::setDate(int day, int month)
mDay = day;
mMonth = month;
}
Ogre::SceneNode* SkyManager::getSunNode()
{
if (!mCreated) return 0;
return mSun->getNode();
}

@ -109,61 +109,68 @@ namespace MWRender
public:
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env);
~SkyManager();
void update(float duration);
void create();
///< no need to call this, automatically done on first enable()
void enable();
void disable();
void setHour (double hour);
///< will be called even when sky is disabled.
void setDate (int day, int month);
///< will be called even when sky is disabled.
int getMasserPhase() const;
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
/// 3 waxing or waning gibbous, 4 full moon
int getSecundaPhase() const;
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
/// 3 waxing or waning gibbous, 4 full moon
void setMoonColour (bool red);
///< change Secunda colour to red
void setCloudsOpacity(float opacity);
///< change opacity of the clouds
void setWeather(const MWWorld::WeatherResult& weather);
Ogre::SceneNode* getSunNode();
void sunEnable();
void sunDisable();
void setSunDirection(const Ogre::Vector3& direction);
void setMasserDirection(const Ogre::Vector3& direction);
void setSecundaDirection(const Ogre::Vector3& direction);
void setMasserFade(const float fade);
void setSecundaFade(const float fade);
void masserEnable();
void masserDisable();
void secundaEnable();
void secundaDisable();
void setThunder(const float factor);
void setGlare(bool glare);
void setGlare(const float glare);
Ogre::Vector3 getRealSunPos();
private:
bool mCreated;
MWWorld::Environment* mEnvironment;
float mHour;
int mDay;
@ -203,12 +210,12 @@ namespace MWRender
float mRemainingTransitionTime;
float mGlareFade;
float mGlare; // target
float mGlareFade; // actual
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
bool mEnabled;
bool mGlareEnabled;
bool mSunEnabled;
bool mMasserEnabled;
bool mSecundaEnabled;

@ -0,0 +1,517 @@
#include <OgreTerrain.h>
#include <OgreTerrainGroup.h>
#include <boost/lexical_cast.hpp>
#include "../mwworld/world.hpp"
#include "terrainmaterial.hpp"
#include "terrain.hpp"
using namespace Ogre;
namespace MWRender
{
//----------------------------------------------------------------------------------------------
TerrainManager::TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& evn) :
mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize))
{
TerrainMaterialGeneratorPtr matGen;
TerrainMaterialGeneratorB* matGenP = new TerrainMaterialGeneratorB();
matGen.bind(matGenP);
mTerrainGlobals.setDefaultMaterialGenerator(matGen);
TerrainMaterialGenerator::Profile* const activeProfile =
mTerrainGlobals.getDefaultMaterialGenerator()
->getActiveProfile();
mActiveProfile = static_cast<TerrainMaterialGeneratorB::SM2Profile*>(activeProfile);
//The pixel error should be as high as possible without it being noticed
//as it governs how fast mesh quality decreases.
mTerrainGlobals.setMaxPixelError(8);
mTerrainGlobals.setLayerBlendMapSize(32);
mTerrainGlobals.setDefaultGlobalColourMapSize(65);
//10 (default) didn't seem to be quite enough
mTerrainGlobals.setSkirtSize(128);
//due to the sudden flick between composite and non composite textures,
//this seemed the distance where it wasn't too noticeable
mTerrainGlobals.setCompositeMapDistance(mWorldSize*2);
mActiveProfile->setLightmapEnabled(false);
mActiveProfile->setLayerSpecularMappingEnabled(false);
mActiveProfile->setLayerNormalMappingEnabled(false);
mActiveProfile->setLayerParallaxMappingEnabled(false);
mActiveProfile->setReceiveDynamicShadowsEnabled(false);
//composite maps lead to a drastic reduction in loading time so are
//disabled
mActiveProfile->setCompositeMapEnabled(false);
mTerrainGroup.setOrigin(Vector3(mWorldSize/2,
0,
-mWorldSize/2));
Terrain::ImportData& importSettings = mTerrainGroup.getDefaultImportSettings();
importSettings.inputBias = 0;
importSettings.terrainSize = mLandSize;
importSettings.worldSize = mWorldSize;
importSettings.minBatchSize = 9;
importSettings.maxBatchSize = mLandSize;
importSettings.deleteInputData = true;
}
//----------------------------------------------------------------------------------------------
TerrainManager::~TerrainManager()
{
}
//----------------------------------------------------------------------------------------------
void TerrainManager::setDiffuse(const ColourValue& diffuse)
{
mTerrainGlobals.setCompositeMapDiffuse(diffuse);
}
//----------------------------------------------------------------------------------------------
void TerrainManager::setAmbient(const ColourValue& ambient)
{
mTerrainGlobals.setCompositeMapAmbient(ambient);
}
//----------------------------------------------------------------------------------------------
void TerrainManager::cellAdded(MWWorld::Ptr::CellStore *store)
{
const int cellX = store->cell->getGridX();
const int cellY = store->cell->getGridY();
ESM::Land* land = mEnvironment.mWorld->getStore().lands.search(cellX, cellY);
if ( land != NULL )
{
if (!land->dataLoaded)
{
land->loadData();
}
}
//split the cell terrain into four segments
const int numTextures = ESM::Land::LAND_TEXTURE_SIZE/2;
for ( int x = 0; x < 2; x++ )
{
for ( int y = 0; y < 2; y++ )
{
Terrain::ImportData terrainData =
mTerrainGroup.getDefaultImportSettings();
const int terrainX = cellX * 2 + x;
const int terrainY = cellY * 2 + y;
//it makes far more sense to reallocate the memory here,
//and let Ogre deal with it due to the issues with deleting
//it at the wrong time if using threads (Which Terrain does)
terrainData.inputFloat = OGRE_ALLOC_T(float,
mLandSize*mLandSize,
MEMCATEGORY_GEOMETRY);
if ( land != NULL )
{
//copy the height data row by row
for ( int terrainCopyY = 0; terrainCopyY < mLandSize; terrainCopyY++ )
{
//the offset of the current segment
const size_t yOffset = y * (mLandSize-1) * ESM::Land::LAND_SIZE +
//offset of the row
terrainCopyY * ESM::Land::LAND_SIZE;
const size_t xOffset = x * (mLandSize-1);
memcpy(&terrainData.inputFloat[terrainCopyY*mLandSize],
&land->landData->heights[yOffset + xOffset],
mLandSize*sizeof(float));
}
}
else
{
memset(terrainData.inputFloat, 0, mLandSize*mLandSize*sizeof(float));
}
std::map<uint16_t, int> indexes;
initTerrainTextures(&terrainData, cellX, cellY,
x * numTextures, y * numTextures,
numTextures, indexes);
if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL)
{
mTerrainGroup.defineTerrain(terrainX, terrainY, &terrainData);
mTerrainGroup.loadTerrain(terrainX, terrainY, true);
Terrain* terrain = mTerrainGroup.getTerrain(terrainX, terrainY);
initTerrainBlendMaps(terrain,
cellX, cellY,
x * numTextures, y * numTextures,
numTextures,
indexes);
if ( land && land->landData->usingColours )
{
// disable or enable global colour map (depends on available vertex colours)
mActiveProfile->setGlobalColourMapEnabled(true);
TexturePtr vertex = getVertexColours(land,
cellX, cellY,
x*(mLandSize-1),
y*(mLandSize-1),
mLandSize);
//this is a hack to get around the fact that Ogre seems to
//corrupt the global colour map leading to rendering errors
MaterialPtr mat = terrain->getMaterial();
mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName( vertex->getName() );
//mat = terrain->_getCompositeMapMaterial();
//mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName( vertex->getName() );
}
else
{
mActiveProfile->setGlobalColourMapEnabled(false);
}
}
}
}
mTerrainGroup.freeTemporaryResources();
}
//----------------------------------------------------------------------------------------------
void TerrainManager::cellRemoved(MWWorld::Ptr::CellStore *store)
{
for ( int x = 0; x < 2; x++ )
{
for ( int y = 0; y < 2; y++ )
{
mTerrainGroup.unloadTerrain(store->cell->getGridX() * 2 + x,
store->cell->getGridY() * 2 + y);
}
}
}
//----------------------------------------------------------------------------------------------
void TerrainManager::initTerrainTextures(Terrain::ImportData* terrainData,
int cellX, int cellY,
int fromX, int fromY, int size,
std::map<uint16_t, int>& indexes)
{
assert(terrainData != NULL && "Must have valid terrain data");
assert(fromX >= 0 && fromY >= 0 &&
"Can't get a terrain texture on terrain outside the current cell");
assert(fromX+size <= ESM::Land::LAND_TEXTURE_SIZE &&
fromY+size <= ESM::Land::LAND_TEXTURE_SIZE &&
"Can't get a terrain texture on terrain outside the current cell");
//this ensures that the ltex indexes are sorted (or retrived as sorted
//which simplifies shading between cells).
//
//If we don't sort the ltex indexes, the splatting order may differ between
//cells which may lead to inconsistent results when shading between cells
std::set<uint16_t> ltexIndexes;
for ( int y = fromY - 1; y < fromY + size + 1; y++ )
{
for ( int x = fromX - 1; x < fromX + size + 1; x++ )
{
ltexIndexes.insert(getLtexIndexAt(cellX, cellY, x, y));
}
}
//there is one texture that we want to use as a base (i.e. it won't have
//a blend map). This holds the ltex index of that base texture so that
//we know not to include it in the output map
int baseTexture = -1;
for ( std::set<uint16_t>::iterator iter = ltexIndexes.begin();
iter != ltexIndexes.end();
++iter )
{
const uint16_t ltexIndex = *iter;
//this is the base texture, so we can ignore this at present
if ( ltexIndex == baseTexture )
{
continue;
}
const std::map<uint16_t, int>::const_iterator it = indexes.find(ltexIndex);
if ( it == indexes.end() )
{
//NB: All vtex ids are +1 compared to the ltex ids
assert( (int)mEnvironment.mWorld->getStore().landTexts.getSize() >= (int)ltexIndex - 1 &&
"LAND.VTEX must be within the bounds of the LTEX array");
std::string texture;
if ( ltexIndex == 0 )
{
texture = "_land_default.dds";
}
else
{
texture = mEnvironment.mWorld->getStore().landTexts.search(ltexIndex-1)->texture;
//TODO this is needed due to MWs messed up texture handling
texture = texture.substr(0, texture.rfind(".")) + ".dds";
}
const size_t position = terrainData->layerList.size();
terrainData->layerList.push_back(Terrain::LayerInstance());
terrainData->layerList[position].worldSize = 256;
terrainData->layerList[position].textureNames.push_back("textures\\" + texture);
if ( baseTexture == -1 )
{
baseTexture = ltexIndex;
}
else
{
indexes[ltexIndex] = position;
}
}
}
}
//----------------------------------------------------------------------------------------------
void TerrainManager::initTerrainBlendMaps(Terrain* terrain,
int cellX, int cellY,
int fromX, int fromY, int size,
const std::map<uint16_t, int>& indexes)
{
assert(terrain != NULL && "Must have valid terrain");
assert(fromX >= 0 && fromY >= 0 &&
"Can't get a terrain texture on terrain outside the current cell");
assert(fromX+size <= ESM::Land::LAND_TEXTURE_SIZE &&
fromY+size <= ESM::Land::LAND_TEXTURE_SIZE &&
"Can't get a terrain texture on terrain outside the current cell");
//size must be a power of 2 as we do divisions with a power of 2 number
//that need to result in an integer for correct splatting
assert( (size & (size - 1)) == 0 && "Size must be a power of 2");
const int blendMapSize = terrain->getLayerBlendMapSize();
const int splatSize = blendMapSize / size;
//zero out every map
std::map<uint16_t, int>::const_iterator iter;
for ( iter = indexes.begin(); iter != indexes.end(); ++iter )
{
float* pBlend = terrain->getLayerBlendMap(iter->second)
->getBlendPointer();
memset(pBlend, 0, sizeof(float) * blendMapSize * blendMapSize);
}
//covert the ltex data into a set of blend maps
for ( int texY = fromY - 1; texY < fromY + size + 1; texY++ )
{
for ( int texX = fromX - 1; texX < fromX + size + 1; texX++ )
{
const uint16_t ltexIndex = getLtexIndexAt(cellX, cellY, texX, texY);
//check if it is the base texture (which isn't in the map) and
//if it is don't bother altering the blend map for it
if ( indexes.find(ltexIndex) == indexes.end() )
{
continue;
}
//while texX is the splat index relative to the entire cell,
//relX is relative to the current segment we are splatting
const int relX = texX - fromX;
const int relY = texY - fromY;
const int layerIndex = indexes.find(ltexIndex)->second;
float* const pBlend = terrain->getLayerBlendMap(layerIndex)
->getBlendPointer();
for ( int y = -1; y < splatSize + 1; y++ )
{
for ( int x = -1; x < splatSize + 1; x++ )
{
//Note: Y is reversed
const int splatY = blendMapSize - 1 - relY * splatSize - y;
const int splatX = relX * splatSize + x;
if ( splatX >= 0 && splatX < blendMapSize &&
splatY >= 0 && splatY < blendMapSize )
{
const int index = (splatY)*blendMapSize + splatX;
if ( y >= 0 && y < splatSize &&
x >= 0 && x < splatSize )
{
pBlend[index] = 1;
}
else
{
//this provides a transition shading but also
//rounds off the corners slightly
pBlend[index] = std::min(1.0f, pBlend[index] + 0.5f);
}
}
}
}
}
}
for ( int i = 1; i < terrain->getLayerCount(); i++ )
{
TerrainLayerBlendMap* blend = terrain->getLayerBlendMap(i);
blend->dirty();
blend->update();
}
}
//----------------------------------------------------------------------------------------------
int TerrainManager::getLtexIndexAt(int cellX, int cellY,
int x, int y)
{
//check texture index falls within the 9 cell bounds
//as this function can't cope with anything above that
assert(x >= -ESM::Land::LAND_TEXTURE_SIZE &&
y >= -ESM::Land::LAND_TEXTURE_SIZE &&
"Trying to get land textures that are out of bounds");
assert(x < 2*ESM::Land::LAND_TEXTURE_SIZE &&
y < 2*ESM::Land::LAND_TEXTURE_SIZE &&
"Trying to get land textures that are out of bounds");
if ( x < 0 )
{
cellX--;
x += ESM::Land::LAND_TEXTURE_SIZE;
}
else if ( x >= ESM::Land::LAND_TEXTURE_SIZE )
{
cellX++;
x -= ESM::Land::LAND_TEXTURE_SIZE;
}
if ( y < 0 )
{
cellY--;
y += ESM::Land::LAND_TEXTURE_SIZE;
}
else if ( y >= ESM::Land::LAND_TEXTURE_SIZE )
{
cellY++;
y -= ESM::Land::LAND_TEXTURE_SIZE;
}
ESM::Land* land = mEnvironment.mWorld->getStore().lands.search(cellX, cellY);
if ( land != NULL )
{
if (!land->dataLoaded)
{
land->loadData();
}
return land->landData
->textures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
}
else
{
return 0;
}
}
//----------------------------------------------------------------------------------------------
TexturePtr TerrainManager::getVertexColours(ESM::Land* land,
int cellX, int cellY,
int fromX, int fromY, int size)
{
TextureManager* const texMgr = TextureManager::getSingletonPtr();
const std::string colourTextureName = "VtexColours_" +
boost::lexical_cast<std::string>(cellX) +
"_" +
boost::lexical_cast<std::string>(cellY) +
"_" +
boost::lexical_cast<std::string>(fromX) +
"_" +
boost::lexical_cast<std::string>(fromY);
TexturePtr tex = texMgr->getByName(colourTextureName);
if ( !tex.isNull() )
{
return tex;
}
tex = texMgr->createManual(colourTextureName,
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
TEX_TYPE_2D, size, size, 0, PF_BYTE_BGR);
HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer();
pixelBuffer->lock(HardwareBuffer::HBL_DISCARD);
const PixelBox& pixelBox = pixelBuffer->getCurrentLock();
uint8* pDest = static_cast<uint8*>(pixelBox.data);
if ( land != NULL )
{
const char* const colours = land->landData->colours;
for ( int y = 0; y < size; y++ )
{
for ( int x = 0; x < size; x++ )
{
const size_t colourOffset = (y+fromY)*3*65 + (x+fromX)*3;
assert( colourOffset < 65*65*3 &&
"Colour offset is out of the expected bounds of record" );
const unsigned char r = colours[colourOffset + 0];
const unsigned char g = colours[colourOffset + 1];
const unsigned char b = colours[colourOffset + 2];
//as is the case elsewhere we need to flip the y
const size_t imageOffset = (size - 1 - y)*size*4 + x*4;
pDest[imageOffset + 0] = b;
pDest[imageOffset + 1] = g;
pDest[imageOffset + 2] = r;
}
}
}
else
{
for ( int y = 0; y < size; y++ )
{
for ( int x = 0; x < size; x++ )
{
for ( int k = 0; k < 3; k++ )
{
*pDest++ = 0;
}
}
}
}
pixelBuffer->unlock();
return tex;
}
}

@ -0,0 +1,117 @@
#ifndef _GAME_RENDER_TERRAIN_H
#define _GAME_RENDER_TERRAIN_H
#include <OgreTerrain.h>
#include <OgreTerrainGroup.h>
#include "terrainmaterial.hpp"
#include "../mwworld/ptr.hpp"
namespace Ogre{
class SceneManager;
class TerrainGroup;
class TerrainGlobalOptions;
class Terrain;
}
namespace MWRender{
/**
* Implements the Morrowind terrain using the Ogre Terrain Component
*
* Each terrain cell is split into four blocks as this leads to an increase
* in performance and means we don't hit splat limits quite as much
*/
class TerrainManager{
public:
TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& env);
virtual ~TerrainManager();
void setDiffuse(const Ogre::ColourValue& diffuse);
void setAmbient(const Ogre::ColourValue& ambient);
void cellAdded(MWWorld::Ptr::CellStore* store);
void cellRemoved(MWWorld::Ptr::CellStore* store);
private:
Ogre::TerrainGlobalOptions mTerrainGlobals;
Ogre::TerrainGroup mTerrainGroup;
const MWWorld::Environment& mEnvironment;
Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile;
/**
* The length in verticies of a single terrain block.
*/
static const int mLandSize = (ESM::Land::LAND_SIZE - 1)/2 + 1;
/**
* The length in game units of a single terrain block.
*/
static const int mWorldSize = ESM::Land::REAL_SIZE/2;
/**
* Setups up the list of textures for part of a cell, using indexes as
* an output to create a mapping of MW LtexIndex to the relevant terrain
* layer
*
* @param terrainData the terrain data to setup the textures for
* @param cellX the coord of the cell
* @param cellY the coord of the cell
* @param fromX the ltex index in the current cell to start making the texture from
* @param fromY the ltex index in the current cell to start making the texture from
* @param size the size (number of splats) to get
* @param indexes a mapping of ltex index to the terrain texture layer that
* can be used by initTerrainBlendMaps
*/
void initTerrainTextures(Ogre::Terrain::ImportData* terrainData,
int cellX, int cellY,
int fromX, int fromY, int size,
std::map<uint16_t, int>& indexes);
/**
* Creates the blend (splatting maps) for the given terrain from the ltex data.
*
* @param terrain the terrain object for the current cell
* @param cellX the coord of the cell
* @param cellY the coord of the cell
* @param fromX the ltex index in the current cell to start making the texture from
* @param fromY the ltex index in the current cell to start making the texture from
* @param size the size (number of splats) to get
* @param indexes the mapping of ltex to blend map produced by initTerrainTextures
*/
void initTerrainBlendMaps(Ogre::Terrain* terrain,
int cellX, int cellY,
int fromX, int fromY, int size,
const std::map<uint16_t, int>& indexes);
/**
* Gets a LTEX index at the given point, assuming the current cell
* starts at (0,0). This supports getting values from the surrounding
* cells so negative x, y is acceptable
*
* @param cellX the coord of the cell
* @param cellY the coord of the cell
* @param x, y the splat position of the ltex index to get relative to the
* first splat of the current cell
*/
int getLtexIndexAt(int cellX, int cellY, int x, int y);
/**
* Due to the fact that Ogre terrain doesn't support vertex colours
* we have to generate them manually
*
* @param cellX the coord of the cell
* @param cellY the coord of the cell
* @param fromX the *vertex* index in the current cell to start making texture from
* @param fromY the *vertex* index in the current cell to start making the texture from
* @param size the size (number of vertexes) to get
*/
Ogre::TexturePtr getVertexColours(ESM::Land* land,
int cellX, int cellY,
int fromX, int fromY, int size);
};
}
#endif // _GAME_RENDER_TERRAIN_H

File diff suppressed because it is too large Load Diff

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

Loading…
Cancel
Save