mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-31 10:36:42 +00:00
Merge branch 'master' of https://github.com/zinnschlag/openmw.git into inventoryGUI
Conflicts: apps/openmw/CMakeLists.txt
This commit is contained in:
commit
a38db39e88
274 changed files with 14152 additions and 6076 deletions
123
Bitstream Vera License.txt
Normal file
123
Bitstream Vera License.txt
Normal file
|
@ -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.
|
139
CMakeLists.txt
139
CMakeLists.txt
|
@ -4,9 +4,6 @@ if (APPLE)
|
||||||
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
||||||
|
|
||||||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
||||||
|
|
||||||
# using 10.6 sdk
|
|
||||||
set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.6.sdk")
|
|
||||||
endif (APPLE)
|
endif (APPLE)
|
||||||
|
|
||||||
# Macros
|
# Macros
|
||||||
|
@ -27,11 +24,17 @@ 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")
|
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)
|
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
|
||||||
|
|
||||||
|
# Apps and tools
|
||||||
|
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
||||||
|
option(BUILD_LAUNCHER "build Launcher" ON)
|
||||||
|
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
|
||||||
|
|
||||||
# Sound source selection
|
# Sound source selection
|
||||||
option(USE_AUDIERE "use Audiere for sound" OFF)
|
|
||||||
option(USE_FFMPEG "use ffmpeg 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)
|
option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
|
||||||
|
|
||||||
find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems")
|
find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems")
|
||||||
|
@ -99,6 +102,7 @@ set(OENGINE_OGRE
|
||||||
${LIBDIR}/openengine/ogre/renderer.cpp
|
${LIBDIR}/openengine/ogre/renderer.cpp
|
||||||
${LIBDIR}/openengine/ogre/mouselook.cpp
|
${LIBDIR}/openengine/ogre/mouselook.cpp
|
||||||
${LIBDIR}/openengine/ogre/fader.cpp
|
${LIBDIR}/openengine/ogre/fader.cpp
|
||||||
|
${LIBDIR}/openengine/ogre/imagerotate.cpp
|
||||||
)
|
)
|
||||||
set(OENGINE_GUI
|
set(OENGINE_GUI
|
||||||
${LIBDIR}/openengine/gui/events.cpp
|
${LIBDIR}/openengine/gui/events.cpp
|
||||||
|
@ -120,54 +124,41 @@ set(OENGINE_BULLET
|
||||||
${LIBDIR}/openengine/bullet/BulletShapeLoader.h
|
${LIBDIR}/openengine/bullet/BulletShapeLoader.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Sound setup
|
set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET})
|
||||||
if (USE_AUDIERE)
|
|
||||||
set(MANGLE_SOUND_OUTPUT
|
|
||||||
${LIBDIR}/mangle/sound/sources/audiere_source.cpp
|
|
||||||
${LIBDIR}/mangle/sound/sources/sample_reader.cpp
|
|
||||||
${LIBDIR}/mangle/stream/clients/audiere_file.cpp)
|
|
||||||
find_package(Audiere REQUIRED)
|
|
||||||
set(SOUND_INPUT_INCLUDES ${AUDIERE_INCLUDE_DIR})
|
|
||||||
set(SOUND_INPUT_LIBRARY ${AUDIERE_LIBRARY})
|
|
||||||
set(SOUND_DEFINE -DOPENMW_USE_AUDIERE)
|
|
||||||
endif (USE_AUDIERE)
|
|
||||||
|
|
||||||
if (USE_FFMPEG)
|
|
||||||
set(MANGLE_SOUND_OUTPUT
|
|
||||||
${LIBDIR}/mangle/sound/sources/ffmpeg_source.cpp)
|
|
||||||
find_package(FFMPEG REQUIRED)
|
|
||||||
set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIR})
|
|
||||||
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES})
|
|
||||||
set(SOUND_DEFINE -DOPENMW_USE_FFMPEG)
|
|
||||||
endif (USE_FFMPEG)
|
|
||||||
|
|
||||||
if (USE_MPG123)
|
|
||||||
set(MANGLE_SOUND_OUTPUT
|
|
||||||
${LIBDIR}/mangle/sound/sources/mpg123_source.cpp
|
|
||||||
${LIBDIR}/mangle/sound/sources/libsndfile.cpp
|
|
||||||
${LIBDIR}/mangle/sound/sources/sample_reader.cpp)
|
|
||||||
find_package(MPG123 REQUIRED)
|
|
||||||
find_package(SNDFILE REQUIRED)
|
|
||||||
set(SOUND_INPUT_INCLUDES ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
|
|
||||||
set(SOUND_INPUT_LIBRARY ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
|
|
||||||
set(SOUND_DEFINE -DOPENMW_USE_MPG123)
|
|
||||||
endif (USE_MPG123)
|
|
||||||
|
|
||||||
set(OENGINE_SOUND
|
|
||||||
# Mangle and OEngine sound files are sort of intertwined, so put
|
|
||||||
# them together here
|
|
||||||
${LIBDIR}/openengine/sound/sndmanager.cpp
|
|
||||||
${LIBDIR}/mangle/sound/outputs/openal_out.cpp
|
|
||||||
${MANGLE_SOUND_OUTPUT}
|
|
||||||
)
|
|
||||||
set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_SOUND} ${OENGINE_BULLET})
|
|
||||||
source_group(libs\\openengine FILES ${OENGINE_ALL})
|
source_group(libs\\openengine FILES ${OENGINE_ALL})
|
||||||
|
|
||||||
set(OPENMW_LIBS ${MANGLE_ALL} ${OENGINE_ALL})
|
set(OPENMW_LIBS ${MANGLE_ALL} ${OENGINE_ALL})
|
||||||
set(OPENMW_LIBS_HEADER)
|
set(OPENMW_LIBS_HEADER)
|
||||||
|
|
||||||
|
# Sound setup
|
||||||
|
set(SOUND_INPUT_INCLUDES "")
|
||||||
|
set(SOUND_INPUT_LIBRARY "")
|
||||||
|
set(SOUND_DEFINE "")
|
||||||
|
if (USE_FFMPEG)
|
||||||
|
find_package(FFMPEG REQUIRED)
|
||||||
|
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIR})
|
||||||
|
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES})
|
||||||
|
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG)
|
||||||
|
endif (USE_FFMPEG)
|
||||||
|
|
||||||
|
if (USE_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)
|
||||||
|
find_package(MPG123 REQUIRED)
|
||||||
|
find_package(SNDFILE REQUIRED)
|
||||||
|
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
|
||||||
|
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
|
||||||
|
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
|
||||||
|
endif (USE_MPG123)
|
||||||
|
|
||||||
# Platform specific
|
# Platform specific
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
set(PLATFORM_INCLUDE_DIR "platform")
|
set(PLATFORM_INCLUDE_DIR "platform")
|
||||||
add_definitions(-DBOOST_ALL_NO_LIB)
|
add_definitions(-DBOOST_ALL_NO_LIB)
|
||||||
else (WIN32)
|
else (WIN32)
|
||||||
|
@ -185,7 +176,7 @@ endif (APPLE)
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
# Fix for not visible pthreads functions for linker with glibc 2.15
|
# Fix for not visible pthreads functions for linker with glibc 2.15
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
find_package (Threads)
|
find_package (Threads)
|
||||||
endif()
|
endif()
|
||||||
|
@ -206,6 +197,7 @@ ENDIF(WIN32)
|
||||||
ENDIF(OGRE_STATIC)
|
ENDIF(OGRE_STATIC)
|
||||||
include_directories("."
|
include_directories("."
|
||||||
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS}
|
${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}
|
${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR}
|
||||||
${PLATFORM_INCLUDE_DIR}
|
${PLATFORM_INCLUDE_DIR}
|
||||||
${MYGUI_INCLUDE_DIRS}
|
${MYGUI_INCLUDE_DIRS}
|
||||||
|
@ -225,6 +217,7 @@ if(APPLE)
|
||||||
"Plugin_ParticleFX")
|
"Plugin_ParticleFX")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
|
add_subdirectory( files/)
|
||||||
add_subdirectory( files/mygui )
|
add_subdirectory( files/mygui )
|
||||||
|
|
||||||
# Specify build paths
|
# Specify build paths
|
||||||
|
@ -237,6 +230,12 @@ endif (APPLE)
|
||||||
|
|
||||||
# Other files
|
# Other files
|
||||||
|
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
|
||||||
|
"${OpenMW_BINARY_DIR}/settings-default.cfg")
|
||||||
|
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg
|
||||||
|
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg")
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||||
|
@ -250,6 +249,9 @@ endif (WIN32)
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux
|
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux
|
||||||
"${OpenMW_BINARY_DIR}/plugins.cfg")
|
"${OpenMW_BINARY_DIR}/plugins.cfg")
|
||||||
|
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
|
||||||
|
"${OpenMW_BINARY_DIR}/openmw.desktop")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -263,8 +265,14 @@ if (APPLE)
|
||||||
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
|
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
|
||||||
|
|
||||||
# prepare plugins
|
# prepare plugins
|
||||||
if (${CMAKE_BUILD_TYPE} MATCHES "Release" OR
|
if (${CMAKE_BUILD_TYPE} MATCHES "Release")
|
||||||
${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo")
|
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})
|
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
|
||||||
else()
|
else()
|
||||||
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
|
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
|
||||||
|
@ -280,7 +288,16 @@ endif (APPLE)
|
||||||
|
|
||||||
# Compiler settings
|
# Compiler settings
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
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)
|
endif (CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
|
||||||
if(DPKG_PROGRAM)
|
if(DPKG_PROGRAM)
|
||||||
|
@ -298,10 +315,12 @@ if(DPKG_PROGRAM)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#Install icon and desktop file
|
#Install icon and desktop file
|
||||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/openmw.desktop" DESTINATION "share/applications/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "share/applications/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
||||||
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(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 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}/transparency-overrides.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}/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")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
||||||
|
|
||||||
|
@ -319,7 +338,7 @@ if(DPKG_PROGRAM)
|
||||||
Data files from the original game is required to run it.")
|
Data files from the original game is required to run it.")
|
||||||
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
|
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
|
||||||
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
|
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
|
||||||
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher")
|
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_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")
|
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
|
||||||
|
@ -340,6 +359,10 @@ if(WIN32)
|
||||||
FILE(GLOB files "${OpenMW_BINARY_DIR}/Release/*.*")
|
FILE(GLOB files "${OpenMW_BINARY_DIR}/Release/*.*")
|
||||||
INSTALL(FILES ${files} DESTINATION ".")
|
INSTALL(FILES ${files} DESTINATION ".")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
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 ".")
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
||||||
|
|
||||||
SET(CPACK_GENERATOR "NSIS")
|
SET(CPACK_GENERATOR "NSIS")
|
||||||
|
@ -349,7 +372,12 @@ if(WIN32)
|
||||||
SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
|
SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
|
||||||
SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
|
SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
|
||||||
SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
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_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt")
|
||||||
SET(CPACK_RESOURCE_FILE_LICENSE "${OpenMW_SOURCE_DIR}/GPL3.txt")
|
SET(CPACK_RESOURCE_FILE_LICENSE "${OpenMW_SOURCE_DIR}/GPL3.txt")
|
||||||
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
||||||
|
@ -393,16 +421,18 @@ add_subdirectory (components)
|
||||||
# Apps and tools
|
# Apps and tools
|
||||||
add_subdirectory( apps/openmw )
|
add_subdirectory( apps/openmw )
|
||||||
|
|
||||||
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
|
||||||
if (BUILD_ESMTOOL)
|
if (BUILD_ESMTOOL)
|
||||||
add_subdirectory( apps/esmtool )
|
add_subdirectory( apps/esmtool )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(BUILD_LAUNCHER "build Launcher inspector" ON)
|
|
||||||
if (BUILD_LAUNCHER)
|
if (BUILD_LAUNCHER)
|
||||||
add_subdirectory( apps/launcher )
|
add_subdirectory( apps/launcher )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (BUILD_MWINIIMPORTER)
|
||||||
|
add_subdirectory( apps/mwiniimporter )
|
||||||
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
if (USE_DEBUG_CONSOLE)
|
if (USE_DEBUG_CONSOLE)
|
||||||
|
@ -492,6 +522,7 @@ if (APPLE)
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||||
|
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
install(FILES "${OpenMW_BINARY_DIR}/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_GENERATOR "DragNDrop")
|
||||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||||
|
|
93
OFL.txt
Normal file
93
OFL.txt
Normal file
|
@ -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")
|
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")
|
||||||
|
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
||||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}launcher.cfg")
|
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.cfg")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -225,7 +225,7 @@ void DataFilesPage::setupDataFiles()
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
msgBox.setStandardButtons(QMessageBox::Cancel);
|
||||||
msgBox.setText(tr("<br><b>Could not find the Data Files location</b><br><br> \
|
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>"));
|
Press \"Browse...\" to specify the location manually.<br>"));
|
||||||
|
|
||||||
QAbstractButton *dirSelectButton =
|
QAbstractButton *dirSelectButton =
|
||||||
|
@ -1057,16 +1057,8 @@ void DataFilesPage::writeConfig(QString profile)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the OpenMW config
|
// Open the OpenMW config as a QFile
|
||||||
QString config = QString::fromStdString((mCfgMgr.getLocalPath() / "openmw.cfg").string());
|
QFile file(QString::fromStdString((mCfgMgr.getUserPath() / "openmw.cfg").string()));
|
||||||
QFile file(config);
|
|
||||||
|
|
||||||
if (!file.exists()) {
|
|
||||||
config = QString::fromStdString((mCfgMgr.getUserPath() / "openmw.cfg").string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the config as a QFile
|
|
||||||
file.setFileName(config);
|
|
||||||
|
|
||||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||||
// File cannot be opened or created
|
// File cannot be opened or created
|
||||||
|
|
|
@ -45,9 +45,28 @@ MainDialog::MainDialog()
|
||||||
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
setMinimumSize(QSize(575, 575));
|
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
|
// Load the stylesheet
|
||||||
QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string());
|
QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string());
|
||||||
QFile file(config);
|
file.setFileName(config);
|
||||||
|
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string()));
|
file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string()));
|
||||||
|
@ -175,6 +194,7 @@ void MainDialog::play()
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
QString game = dir.absoluteFilePath("openmw");
|
QString game = dir.absoluteFilePath("openmw");
|
||||||
QFile file(game);
|
QFile file(game);
|
||||||
|
game = "\"" + game + "\"";
|
||||||
#else
|
#else
|
||||||
QString game = "./openmw";
|
QString game = "./openmw";
|
||||||
QFile file(game);
|
QFile file(game);
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 50 KiB |
20
apps/mwiniimporter/CMakeLists.txt
Normal file
20
apps/mwiniimporter/CMakeLists.txt
Normal file
|
@ -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
|
||||||
|
)
|
||||||
|
|
216
apps/mwiniimporter/importer.cpp
Normal file
216
apps/mwiniimporter/importer.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
apps/mwiniimporter/importer.hpp
Normal file
34
apps/mwiniimporter/importer.hpp
Normal file
|
@ -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
|
75
apps/mwiniimporter/main.cpp
Normal file
75
apps/mwiniimporter/main.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||||
|
|
||||||
add_openmw_dir (mwrender
|
add_openmw_dir (mwrender
|
||||||
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
||||||
renderinginterface localmap
|
renderinginterface localmap occlusionquery terrain terrainmaterial water shadows shaderhelper
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
@ -25,6 +25,7 @@ add_openmw_dir (mwinput
|
||||||
add_openmw_dir (mwgui
|
add_openmw_dir (mwgui
|
||||||
layouts text_input widgets race class birth review window_manager console dialogue
|
layouts text_input widgets race class birth review window_manager console dialogue
|
||||||
dialogue_history window_base stats_window messagebox journalwindow charactercreation container
|
dialogue_history window_base stats_window messagebox journalwindow charactercreation container
|
||||||
|
map_window window_pinnable_base cursorreplace
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwdialogue
|
add_openmw_dir (mwdialogue
|
||||||
|
@ -39,7 +40,7 @@ add_openmw_dir (mwscript
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwsound
|
add_openmw_dir (mwsound
|
||||||
soundmanager
|
soundmanager openal_output audiere_decoder mpgsnd_decoder ffmpeg_decoder
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwworld
|
add_openmw_dir (mwworld
|
||||||
|
@ -54,7 +55,7 @@ add_openmw_dir (mwclass
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanager stat creaturestats magiceffects movement
|
mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells
|
||||||
)
|
)
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
|
@ -82,6 +83,7 @@ add_definitions(${SOUND_DEFINE})
|
||||||
|
|
||||||
target_link_libraries(openmw
|
target_link_libraries(openmw
|
||||||
${OGRE_LIBRARIES}
|
${OGRE_LIBRARIES}
|
||||||
|
${OGRE_Terrain_LIBRARY}
|
||||||
${OGRE_STATIC_PLUGINS}
|
${OGRE_STATIC_PLUGINS}
|
||||||
${OIS_LIBRARIES}
|
${OIS_LIBRARIES}
|
||||||
${Boost_LIBRARIES}
|
${Boost_LIBRARIES}
|
||||||
|
@ -89,7 +91,7 @@ target_link_libraries(openmw
|
||||||
${SOUND_INPUT_LIBRARY}
|
${SOUND_INPUT_LIBRARY}
|
||||||
${BULLET_LIBRARIES}
|
${BULLET_LIBRARIES}
|
||||||
${MYGUI_LIBRARIES}
|
${MYGUI_LIBRARIES}
|
||||||
MyGUI.OgrePlatform #TODO MyGUI ogre platform is not added by the find script
|
${MYGUI_PLATFORM_LIBRARIES}
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include <components/esm/esm_reader.hpp>
|
#include <components/esm/esm_reader.hpp>
|
||||||
#include <components/files/fixedpath.hpp>
|
#include <components/files/fixedpath.hpp>
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/nifoverrides/nifoverrides.hpp>
|
||||||
|
|
||||||
#include <components/nifbullet/bullet_nif_loader.hpp>
|
#include <components/nifbullet/bullet_nif_loader.hpp>
|
||||||
#include <components/nifogre/ogre_nif_loader.hpp>
|
#include <components/nifogre/ogre_nif_loader.hpp>
|
||||||
|
@ -27,6 +29,7 @@
|
||||||
#include "mwinput/inputmanager.hpp"
|
#include "mwinput/inputmanager.hpp"
|
||||||
|
|
||||||
#include "mwgui/window_manager.hpp"
|
#include "mwgui/window_manager.hpp"
|
||||||
|
#include "mwgui/cursorreplace.hpp"
|
||||||
|
|
||||||
#include "mwscript/scriptmanager.hpp"
|
#include "mwscript/scriptmanager.hpp"
|
||||||
#include "mwscript/compilercontext.hpp"
|
#include "mwscript/compilercontext.hpp"
|
||||||
|
@ -82,12 +85,20 @@ void OMW::Engine::updateFocusReport (float duration)
|
||||||
|
|
||||||
if (!handle.empty())
|
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()){
|
if (!ptr.isEmpty()){
|
||||||
name = MWWorld::Class::get (ptr).getName (ptr);
|
name = MWWorld::Class::get (ptr).getName (ptr);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (std::runtime_error& e)
|
||||||
|
{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name!=mFocusName)
|
if (name!=mFocusName)
|
||||||
|
@ -115,13 +126,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
||||||
{
|
{
|
||||||
mEnvironment.mFrameDuration = evt.timeSinceLastFrame;
|
mEnvironment.mFrameDuration = evt.timeSinceLastFrame;
|
||||||
|
|
||||||
|
// update input
|
||||||
|
mEnvironment.mInputManager->update();
|
||||||
|
|
||||||
// sound
|
// sound
|
||||||
if (mUseSound)
|
if (mUseSound)
|
||||||
{
|
|
||||||
mEnvironment.mSoundManager->playPlaylist();
|
|
||||||
|
|
||||||
mEnvironment.mSoundManager->update (evt.timeSinceLastFrame);
|
mEnvironment.mSoundManager->update (evt.timeSinceLastFrame);
|
||||||
}
|
|
||||||
|
|
||||||
// update GUI
|
// update GUI
|
||||||
Ogre::RenderWindow* window = mOgre->getWindow();
|
Ogre::RenderWindow* window = mOgre->getWindow();
|
||||||
|
@ -152,7 +162,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
||||||
|
|
||||||
// update actors
|
// update actors
|
||||||
std::vector<std::pair<std::string, Ogre::Vector3> > movement;
|
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)
|
if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game)
|
||||||
mEnvironment.mWorld->doPhysics (movement, mEnvironment.mFrameDuration);
|
mEnvironment.mWorld->doPhysics (movement, mEnvironment.mFrameDuration);
|
||||||
|
@ -208,13 +219,18 @@ OMW::Engine::~Engine()
|
||||||
void OMW::Engine::loadBSA()
|
void OMW::Engine::loadBSA()
|
||||||
{
|
{
|
||||||
const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa");
|
const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa");
|
||||||
std::string dataDirectory;
|
|
||||||
for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter)
|
for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter)
|
||||||
{
|
{
|
||||||
std::cout << "Adding " << iter->second.string() << std::endl;
|
std::cout << "Adding " << iter->second.string() << std::endl;
|
||||||
Bsa::addBSA(iter->second.string());
|
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;
|
std::cout << "Data dir " << dataDirectory << std::endl;
|
||||||
Bsa::addDir(dataDirectory, mFSStrict);
|
Bsa::addDir(dataDirectory, mFSStrict);
|
||||||
}
|
}
|
||||||
|
@ -312,6 +328,36 @@ void OMW::Engine::go()
|
||||||
{
|
{
|
||||||
boost::filesystem::create_directories(configPath);
|
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");
|
||||||
|
|
||||||
|
// load nif overrides
|
||||||
|
NifOverrides::Overrides nifOverrides;
|
||||||
|
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg"))
|
||||||
|
nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg");
|
||||||
|
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"))
|
||||||
|
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg");
|
||||||
|
|
||||||
mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()),
|
mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()),
|
||||||
mCfgMgr.getOgreConfigPath().string(),
|
mCfgMgr.getOgreConfigPath().string(),
|
||||||
mCfgMgr.getLogPath().string(),
|
mCfgMgr.getLogPath().string(),
|
||||||
|
@ -319,16 +365,25 @@ void OMW::Engine::go()
|
||||||
|
|
||||||
// This has to be added BEFORE MyGUI is initialized, as it needs
|
// This has to be added BEFORE MyGUI is initialized, as it needs
|
||||||
// to find core.xml here.
|
// to find core.xml here.
|
||||||
|
|
||||||
|
//addResourcesDirectory(mResDir);
|
||||||
|
|
||||||
addResourcesDirectory(mResDir / "mygui");
|
addResourcesDirectory(mResDir / "mygui");
|
||||||
|
addResourcesDirectory(mResDir / "water");
|
||||||
|
addResourcesDirectory(mResDir / "gbuffer");
|
||||||
|
addResourcesDirectory(mResDir / "shadows");
|
||||||
|
|
||||||
// Create the window
|
// Create the window
|
||||||
mOgre->createWindow("OpenMW");
|
mOgre->createWindow("OpenMW");
|
||||||
|
|
||||||
loadBSA();
|
loadBSA();
|
||||||
|
|
||||||
|
// cursor replacer (converts the cursor from the bsa so they can be used by mygui)
|
||||||
|
MWGui::CursorReplace replacer;
|
||||||
|
|
||||||
// Create the world
|
// Create the world
|
||||||
mEnvironment.mWorld = new MWWorld::World (*mOgre, mFileCollections, mMaster,
|
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
|
// Create window manager - this manages all the MW-specific GUI windows
|
||||||
MWScript::registerExtensions (mExtensions);
|
MWScript::registerExtensions (mExtensions);
|
||||||
|
@ -337,10 +392,7 @@ void OMW::Engine::go()
|
||||||
mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"));
|
mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"));
|
||||||
|
|
||||||
// Create sound system
|
// Create sound system
|
||||||
mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(),
|
mEnvironment.mSoundManager = new MWSound::SoundManager(mUseSound, mEnvironment);
|
||||||
mOgre->getCamera(),
|
|
||||||
mDataDirs,
|
|
||||||
mUseSound, mFSStrict, mEnvironment);
|
|
||||||
|
|
||||||
// Create script system
|
// Create script system
|
||||||
mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full,
|
mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full,
|
||||||
|
@ -405,6 +457,9 @@ void OMW::Engine::go()
|
||||||
// Start the main rendering loop
|
// Start the main rendering loop
|
||||||
mOgre->start();
|
mOgre->start();
|
||||||
|
|
||||||
|
// Save user settings
|
||||||
|
settings.saveUser(settingspath);
|
||||||
|
|
||||||
std::cout << "Quitting peacefully.\n";
|
std::cout << "Quitting peacefully.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,10 +473,21 @@ void OMW::Engine::activate()
|
||||||
if (handle.empty())
|
if (handle.empty())
|
||||||
return;
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MWScript::InterpreterContext interpreterContext (mEnvironment,
|
MWScript::InterpreterContext interpreterContext (mEnvironment,
|
||||||
&ptr.getRefData().getLocals(), ptr);
|
&ptr.getRefData().getLocals(), ptr);
|
||||||
|
@ -487,3 +553,8 @@ void OMW::Engine::setEncoding(const std::string& encoding)
|
||||||
{
|
{
|
||||||
mEncoding = encoding;
|
mEncoding = encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OMW::Engine::setFallbackValues(std::map<std::string,std::string> fallbackMap)
|
||||||
|
{
|
||||||
|
mFallbackMap = fallbackMap;
|
||||||
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ namespace OMW
|
||||||
bool mReportFocus;
|
bool mReportFocus;
|
||||||
float mFocusTDiff;
|
float mFocusTDiff;
|
||||||
std::string mFocusName;
|
std::string mFocusName;
|
||||||
|
std::map<std::string,std::string> mFallbackMap;
|
||||||
|
|
||||||
MWWorld::Environment mEnvironment;
|
MWWorld::Environment mEnvironment;
|
||||||
Compiler::Extensions mExtensions;
|
Compiler::Extensions mExtensions;
|
||||||
|
@ -163,6 +164,8 @@ namespace OMW
|
||||||
|
|
||||||
void setAnimationVerbose(bool animverbose);
|
void setAnimationVerbose(bool animverbose);
|
||||||
|
|
||||||
|
void setFallbackValues(std::map<std::string,std::string> map);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Files::ConfigurationManager& mCfgMgr;
|
Files::ConfigurationManager& mCfgMgr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,6 +54,41 @@ inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string
|
||||||
|
|
||||||
using namespace std;
|
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
|
* \brief Parses application command line and calls \ref Cfg::ConfigurationManager
|
||||||
* to parse configuration files.
|
* 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(), "")
|
("plugin", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||||
->multitoken(), "plugin file(s)")
|
->multitoken(), "plugin file(s)")
|
||||||
|
|
||||||
("fps", boost::program_options::value<int>()->implicit_value(1)
|
("anim-verbose", bpo::value<bool>()->implicit_value(true)
|
||||||
->default_value(0), "fps counter detail (0 = off, 1 = fps counter, 2 = full detail)")
|
|
||||||
|
|
||||||
("anim-verbose", boost::program_options::value<bool>()->implicit_value(true)
|
|
||||||
->default_value(false), "output animation indices files")
|
->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")
|
->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")
|
->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")
|
->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")
|
->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")
|
->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)")
|
->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"),
|
default_value("win1252"),
|
||||||
"Character encoding used in OpenMW game messages:\n"
|
"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\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\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||||
"\n\twin1252 - Western European (Latin) alphabet, used by default")
|
"\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")
|
->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)
|
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>());
|
engine.setNewGame(variables["new-game"].as<bool>());
|
||||||
|
|
||||||
// other settings
|
// other settings
|
||||||
engine.showFPS(variables["fps"].as<int>());
|
|
||||||
engine.setDebugMode(variables["debug"].as<bool>());
|
engine.setDebugMode(variables["debug"].as<bool>());
|
||||||
engine.setSoundUsage(!variables["nosound"].as<bool>());
|
engine.setSoundUsage(!variables["nosound"].as<bool>());
|
||||||
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
||||||
engine.setCompileAll(variables["script-all"].as<bool>());
|
engine.setCompileAll(variables["script-all"].as<bool>());
|
||||||
engine.setReportFocus(variables["report-focus"].as<bool>());
|
engine.setReportFocus(variables["report-focus"].as<bool>());
|
||||||
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
|
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
|
||||||
|
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -70,6 +70,14 @@ namespace MWClass
|
||||||
return ref->base->script;
|
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()
|
void Apparatus::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Apparatus);
|
boost::shared_ptr<Class> instance (new Apparatus);
|
||||||
|
|
|
@ -25,6 +25,9 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const;
|
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,
|
boost::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -160,6 +160,14 @@ namespace MWClass
|
||||||
return ESM::Skill::HeavyArmor;
|
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()
|
void Armor::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Armor);
|
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
|
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||||
/// no such skill.
|
/// 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// TODO implement reading
|
// 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> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -72,6 +72,14 @@ namespace MWClass
|
||||||
return ref->base->script;
|
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()
|
void Book::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Book);
|
boost::shared_ptr<Class> instance (new Book);
|
||||||
|
|
|
@ -25,6 +25,9 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
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,
|
boost::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -123,6 +123,14 @@ namespace MWClass
|
||||||
return -1;
|
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()
|
void Clothing::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Clothing);
|
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
|
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||||
/// no such skill.
|
/// 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
|
|
@ -87,7 +87,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// TODO check for key
|
// TODO check for key
|
||||||
std::cout << "Locked container" << std::endl;
|
std::cout << "Locked container" << std::endl;
|
||||||
environment.mSoundManager->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);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -103,7 +103,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// Trap activation goes here
|
// Trap activation goes here
|
||||||
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
||||||
environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0, false);
|
environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0);
|
||||||
ptr.getCellRef().trap = "";
|
ptr.getCellRef().trap = "";
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace MWClass
|
||||||
// TODO check for key
|
// TODO check for key
|
||||||
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
|
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
|
||||||
std::cout << "Locked!" << std::endl;
|
std::cout << "Locked!" << std::endl;
|
||||||
environment.mSoundManager->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);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// Trap activation
|
// Trap activation
|
||||||
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
||||||
environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0, false);
|
environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0);
|
||||||
ptr.getCellRef().trap = "";
|
ptr.getCellRef().trap = "";
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ namespace MWClass
|
||||||
// TODO return action for rotating the door
|
// TODO return action for rotating the door
|
||||||
|
|
||||||
// This is a little pointless, but helps with testing
|
// This is a little pointless, but helps with testing
|
||||||
environment.mSoundManager->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);
|
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,
|
boost::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -68,6 +68,14 @@ namespace MWClass
|
||||||
return ref->base->script;
|
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()
|
void Ingredient::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Ingredient);
|
boost::shared_ptr<Class> instance (new Ingredient);
|
||||||
|
|
|
@ -25,6 +25,9 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace MWClass
|
||||||
|
|
||||||
if (!ref->base->sound.empty())
|
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))
|
if (!(ref->base->data.flags & ESM::Light::Carry))
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
|
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -110,6 +110,14 @@ namespace MWClass
|
||||||
return std::make_pair (slots, false);
|
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()
|
void Light::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Light);
|
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
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
/// stay stacked when equipped?
|
/// 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
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,
|
boost::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -81,6 +81,14 @@ namespace MWClass
|
||||||
return std::make_pair (slots, false);
|
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()
|
void Lockpick::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Lockpick);
|
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
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
/// stay stacked when equipped?
|
/// 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
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,
|
boost::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -70,6 +70,14 @@ namespace MWClass
|
||||||
return ref->base->script;
|
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()
|
void Miscellaneous::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Miscellaneous);
|
boost::shared_ptr<Class> instance (new Miscellaneous);
|
||||||
|
|
|
@ -25,6 +25,9 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
|
|
@ -53,28 +53,40 @@ namespace MWClass
|
||||||
// NPC stats
|
// NPC stats
|
||||||
if (!ref->base->faction.empty())
|
if (!ref->base->faction.empty())
|
||||||
{
|
{
|
||||||
// TODO research how initial rank is stored. The information in loadnpc.hpp are at
|
if(ref->base->npdt52.gold != -10)
|
||||||
// best very unclear.
|
{
|
||||||
data->mNpcStats.mFactionRank[ref->base->faction] = 0;
|
data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt52.rank;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt12.rank;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<27; ++i)
|
if(ref->base->npdt52.gold != -10)
|
||||||
data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]);
|
{
|
||||||
|
for (int i=0; i<27; ++i)
|
||||||
|
data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]);
|
||||||
|
|
||||||
// creature stats
|
// creature stats
|
||||||
data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength);
|
data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength);
|
||||||
data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence);
|
data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence);
|
||||||
data->mCreatureStats.mAttributes[2].set (ref->base->npdt52.willpower);
|
data->mCreatureStats.mAttributes[2].set (ref->base->npdt52.willpower);
|
||||||
data->mCreatureStats.mAttributes[3].set (ref->base->npdt52.agility);
|
data->mCreatureStats.mAttributes[3].set (ref->base->npdt52.agility);
|
||||||
data->mCreatureStats.mAttributes[4].set (ref->base->npdt52.speed);
|
data->mCreatureStats.mAttributes[4].set (ref->base->npdt52.speed);
|
||||||
data->mCreatureStats.mAttributes[5].set (ref->base->npdt52.endurance);
|
data->mCreatureStats.mAttributes[5].set (ref->base->npdt52.endurance);
|
||||||
data->mCreatureStats.mAttributes[6].set (ref->base->npdt52.personality);
|
data->mCreatureStats.mAttributes[6].set (ref->base->npdt52.personality);
|
||||||
data->mCreatureStats.mAttributes[7].set (ref->base->npdt52.luck);
|
data->mCreatureStats.mAttributes[7].set (ref->base->npdt52.luck);
|
||||||
data->mCreatureStats.mDynamic[0].set (ref->base->npdt52.health);
|
data->mCreatureStats.mDynamic[0].set (ref->base->npdt52.health);
|
||||||
data->mCreatureStats.mDynamic[1].set (ref->base->npdt52.mana);
|
data->mCreatureStats.mDynamic[1].set (ref->base->npdt52.mana);
|
||||||
data->mCreatureStats.mDynamic[2].set (ref->base->npdt52.fatigue);
|
data->mCreatureStats.mDynamic[2].set (ref->base->npdt52.fatigue);
|
||||||
|
|
||||||
data->mCreatureStats.mLevel = ref->base->npdt52.level;
|
data->mCreatureStats.mLevel = ref->base->npdt52.level;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: do something with npdt12 maybe:p
|
||||||
|
}
|
||||||
|
|
||||||
// \todo add initial container content
|
// \todo add initial container content
|
||||||
|
|
||||||
|
@ -281,7 +293,7 @@ namespace MWClass
|
||||||
void Npc::registerSelf()
|
void Npc::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Npc);
|
boost::shared_ptr<Class> instance (new Npc);
|
||||||
|
std::cout << "class npc:" << typeid (ESM::NPC).name();
|
||||||
registerClass (typeid (ESM::NPC).name(), instance);
|
registerClass (typeid (ESM::NPC).name(), instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace MWClass
|
||||||
boost::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
|
boost::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -70,6 +70,14 @@ namespace MWClass
|
||||||
return ref->base->script;
|
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()
|
void Potion::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Potion);
|
boost::shared_ptr<Class> instance (new Potion);
|
||||||
|
|
|
@ -25,6 +25,9 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
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,
|
boost::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -80,6 +80,14 @@ namespace MWClass
|
||||||
return std::make_pair (slots, false);
|
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()
|
void Probe::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Probe);
|
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
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
/// stay stacked when equipped?
|
/// 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
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,
|
boost::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -70,6 +70,14 @@ namespace MWClass
|
||||||
return ref->base->script;
|
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()
|
void Repair::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Repair);
|
boost::shared_ptr<Class> instance (new Repair);
|
||||||
|
|
|
@ -25,6 +25,9 @@ namespace MWClass
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
virtual 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
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,
|
boost::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||||
{
|
{
|
||||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
|
||||||
|
|
||||||
return boost::shared_ptr<MWWorld::Action> (
|
return boost::shared_ptr<MWWorld::Action> (
|
||||||
new MWWorld::ActionTake (ptr));
|
new MWWorld::ActionTake (ptr));
|
||||||
|
@ -139,6 +139,14 @@ namespace MWClass
|
||||||
return -1;
|
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()
|
void Weapon::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new Weapon);
|
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
|
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||||
/// no such skill.
|
/// 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();
|
static void registerSelf();
|
||||||
|
|
||||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
#include "../mwscript/interpretercontext.hpp"
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
#include <components/compiler/scriptparser.hpp>
|
#include <components/compiler/scriptparser.hpp>
|
||||||
|
|
||||||
|
#include "../mwclass/npc.hpp"
|
||||||
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
std::string toLower (const std::string& name)
|
std::string toLower (const std::string& name)
|
||||||
|
@ -109,16 +112,15 @@ namespace
|
||||||
switch (world.getGlobalVariableType (name))
|
switch (world.getGlobalVariableType (name))
|
||||||
{
|
{
|
||||||
case 's':
|
case 's':
|
||||||
|
return selectCompare (comp, world.getGlobalVariable (name).mShort, value);
|
||||||
return selectCompare (comp, value, world.getGlobalVariable (name).mShort);
|
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
||||||
return selectCompare (comp, value, world.getGlobalVariable (name).mLong);
|
return selectCompare (comp, world.getGlobalVariable (name).mLong, value);
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
||||||
return selectCompare (comp, value, world.getGlobalVariable (name).mFloat);
|
return selectCompare (comp, world.getGlobalVariable (name).mFloat, value);
|
||||||
|
|
||||||
case ' ':
|
case ' ':
|
||||||
|
|
||||||
|
@ -178,7 +180,17 @@ namespace MWDialogue
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 46://Same faction
|
case 46://Same faction
|
||||||
if(!selectCompare<int,int>(comp,0,select.i)) return false;
|
{
|
||||||
|
MWMechanics::NpcStats PCstats = MWWorld::Class::get(mEnvironment.mWorld->getPlayer().getPlayer()).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer());
|
||||||
|
MWMechanics::NpcStats NPCstats = MWWorld::Class::get(actor).getNpcStats(actor);
|
||||||
|
int sameFaction = 0;
|
||||||
|
if(!NPCstats.mFactionRank.empty())
|
||||||
|
{
|
||||||
|
std::string NPCFaction = NPCstats.mFactionRank.begin()->first;
|
||||||
|
if(PCstats.mFactionRank.find(NPCFaction) != PCstats.mFactionRank.end()) sameFaction = 1;
|
||||||
|
}
|
||||||
|
if(!selectCompare<int,int>(comp,sameFaction,select.i)) return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 48://Detected
|
case 48://Detected
|
||||||
|
@ -190,7 +202,6 @@ namespace MWDialogue
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 50://choice
|
case 50://choice
|
||||||
|
|
||||||
if(choice)
|
if(choice)
|
||||||
{
|
{
|
||||||
if(!selectCompare<int,int>(comp,mChoice,select.i)) return false;
|
if(!selectCompare<int,int>(comp,mChoice,select.i)) return false;
|
||||||
|
@ -270,7 +281,7 @@ namespace MWDialogue
|
||||||
{
|
{
|
||||||
case '1': // function
|
case '1': // function
|
||||||
|
|
||||||
return true; // TODO implement functions
|
return true; // Done elsewhere.
|
||||||
|
|
||||||
case '2': // global
|
case '2': // global
|
||||||
|
|
||||||
|
@ -444,9 +455,6 @@ namespace MWDialogue
|
||||||
if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor))
|
if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//PC Faction
|
|
||||||
if(!info.pcFaction.empty()) return false;
|
|
||||||
|
|
||||||
//NPC race
|
//NPC race
|
||||||
if (!info.race.empty())
|
if (!info.race.empty())
|
||||||
{
|
{
|
||||||
|
@ -474,26 +482,37 @@ namespace MWDialogue
|
||||||
//NPC faction
|
//NPC faction
|
||||||
if (!info.npcFaction.empty())
|
if (!info.npcFaction.empty())
|
||||||
{
|
{
|
||||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *cellRef = actor.get<ESM::NPC>();
|
//MWWorld::Class npcClass = MWWorld::Class::get(actor);
|
||||||
|
MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor);
|
||||||
if (!cellRef)
|
std::map<std::string,int>::iterator it = stats.mFactionRank.find(info.npcFaction);
|
||||||
return false;
|
if(it!=stats.mFactionRank.end())
|
||||||
|
|
||||||
if (toLower (info.npcFaction)!=toLower (cellRef->base->faction))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//check NPC rank
|
|
||||||
if(cellRef->base->npdt52.gold != -10)
|
|
||||||
{
|
{
|
||||||
if(cellRef->base->npdt52.rank < info.data.rank) return false;
|
//check rank
|
||||||
|
if(it->second < (int)info.data.rank) return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(cellRef->base->npdt12.rank < info.data.rank) return false;
|
//not in the faction
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO check player faction
|
// TODO check player faction
|
||||||
|
if(!info.pcFaction.empty())
|
||||||
|
{
|
||||||
|
MWMechanics::NpcStats stats = MWWorld::Class::get(mEnvironment.mWorld->getPlayer().getPlayer()).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer());
|
||||||
|
std::map<std::string,int>::iterator it = stats.mFactionRank.find(info.pcFaction);
|
||||||
|
if(it!=stats.mFactionRank.end())
|
||||||
|
{
|
||||||
|
//check rank
|
||||||
|
if(it->second < (int)info.data.PCrank) return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//not in the faction
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//check gender
|
//check gender
|
||||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>();
|
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>();
|
||||||
|
@ -528,6 +547,13 @@ namespace MWDialogue
|
||||||
mChoice = -1;
|
mChoice = -1;
|
||||||
mIsInChoice = false;
|
mIsInChoice = false;
|
||||||
mCompilerContext.setExtensions (&extensions);
|
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)
|
void DialogueManager::addTopic(std::string topic)
|
||||||
|
@ -563,13 +589,7 @@ namespace MWDialogue
|
||||||
|
|
||||||
mActor = actor;
|
mActor = actor;
|
||||||
|
|
||||||
mDialogueMap.clear();
|
|
||||||
actorKnownTopics.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
|
//initialise the GUI
|
||||||
mEnvironment.mInputManager->setGuiMode(MWGui::GM_Dialogue);
|
mEnvironment.mInputManager->setGuiMode(MWGui::GM_Dialogue);
|
||||||
|
@ -582,6 +602,7 @@ namespace MWDialogue
|
||||||
//greeting
|
//greeting
|
||||||
bool greetingFound = false;
|
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;
|
||||||
|
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++)
|
for(ESMS::RecListT<ESM::Dialogue>::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++)
|
||||||
{
|
{
|
||||||
ESM::Dialogue ndialogue = it->second;
|
ESM::Dialogue ndialogue = it->second;
|
||||||
|
@ -656,6 +677,7 @@ namespace MWDialogue
|
||||||
|
|
||||||
void DialogueManager::executeScript(std::string script)
|
void DialogueManager::executeScript(std::string script)
|
||||||
{
|
{
|
||||||
|
std::cout << script;
|
||||||
std::vector<Interpreter::Type_Code> code;
|
std::vector<Interpreter::Type_Code> code;
|
||||||
if(compile(script,code))
|
if(compile(script,code))
|
||||||
{
|
{
|
||||||
|
@ -797,4 +819,19 @@ namespace MWDialogue
|
||||||
mChoiceMap[question] = choice;
|
mChoiceMap[question] = choice;
|
||||||
mIsInChoice = true;
|
mIsInChoice = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string DialogueManager::getFaction()
|
||||||
|
{
|
||||||
|
std::string factionID("");
|
||||||
|
MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
|
||||||
|
if(stats.mFactionRank.empty())
|
||||||
|
{
|
||||||
|
std::cout << "No faction for this actor!";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
factionID = stats.mFactionRank.begin()->first;
|
||||||
|
}
|
||||||
|
return factionID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,9 @@ namespace MWDialogue
|
||||||
|
|
||||||
void askQuestion(std::string question,int choice);
|
void askQuestion(std::string question,int choice);
|
||||||
|
|
||||||
|
///get the faction of the actor you are talking with
|
||||||
|
std::string getFaction();
|
||||||
|
|
||||||
//calbacks for the GUI
|
//calbacks for the GUI
|
||||||
void keywordSelected(std::string keyword);
|
void keywordSelected(std::string keyword);
|
||||||
void goodbyeSelected();
|
void goodbyeSelected();
|
||||||
|
|
16
apps/openmw/mwgui/cursorreplace.cpp
Normal file
16
apps/openmw/mwgui/cursorreplace.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "cursorreplace.hpp"
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <openengine/ogre/imagerotate.hpp>
|
||||||
|
|
||||||
|
#include <OgreResourceGroupManager.h>
|
||||||
|
#include <OgreRoot.h>
|
||||||
|
|
||||||
|
using namespace MWGui;
|
||||||
|
|
||||||
|
CursorReplace::CursorReplace()
|
||||||
|
{
|
||||||
|
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90);
|
||||||
|
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45);
|
||||||
|
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45);
|
||||||
|
}
|
16
apps/openmw/mwgui/cursorreplace.hpp
Normal file
16
apps/openmw/mwgui/cursorreplace.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef GAME_CURSORREPLACE_H
|
||||||
|
#define GAME_CURSORREPLACE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
/// \brief MyGUI does not support rotating cursors, so we have to do it manually
|
||||||
|
class CursorReplace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CursorReplace();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -43,9 +43,6 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environm
|
||||||
// Centre dialog
|
// Centre dialog
|
||||||
center();
|
center();
|
||||||
|
|
||||||
//WindowManager *wm = environment.mWindowManager;
|
|
||||||
setText("NpcName", "Name of character");
|
|
||||||
|
|
||||||
//History view
|
//History view
|
||||||
getWidget(history, "History");
|
getWidget(history, "History");
|
||||||
history->setOverflowToTheLeft(true);
|
history->setOverflowToTheLeft(true);
|
||||||
|
@ -116,7 +113,8 @@ void DialogueWindow::onSelectTopic(MyGUI::ListBox* _sender, size_t _index)
|
||||||
|
|
||||||
void DialogueWindow::startDialogue(std::string npcName)
|
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)
|
void DialogueWindow::setKeywords(std::list<std::string> keyWords)
|
||||||
|
|
|
@ -15,6 +15,27 @@ using namespace MWGui;
|
||||||
|
|
||||||
HUD::HUD(int width, int height, int fpsLevel)
|
HUD::HUD(int width, int height, int fpsLevel)
|
||||||
: Layout("openmw_hud_layout.xml")
|
: 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);
|
setCoord(0,0, width, height);
|
||||||
|
|
||||||
|
@ -22,32 +43,32 @@ HUD::HUD(int width, int height, int fpsLevel)
|
||||||
getWidget(health, "Health");
|
getWidget(health, "Health");
|
||||||
getWidget(magicka, "Magicka");
|
getWidget(magicka, "Magicka");
|
||||||
getWidget(stamina, "Stamina");
|
getWidget(stamina, "Stamina");
|
||||||
|
hmsBaseLeft = health->getLeft();
|
||||||
|
|
||||||
// Item and spell images and status bars
|
// Item and spell images and status bars
|
||||||
|
getWidget(weapBox, "WeapBox");
|
||||||
getWidget(weapImage, "WeapImage");
|
getWidget(weapImage, "WeapImage");
|
||||||
getWidget(weapStatus, "WeapStatus");
|
getWidget(weapStatus, "WeapStatus");
|
||||||
|
weapBoxBaseLeft = weapBox->getLeft();
|
||||||
|
|
||||||
|
getWidget(spellBox, "SpellBox");
|
||||||
getWidget(spellImage, "SpellImage");
|
getWidget(spellImage, "SpellImage");
|
||||||
getWidget(spellStatus, "SpellStatus");
|
getWidget(spellStatus, "SpellStatus");
|
||||||
|
spellBoxBaseLeft = spellBox->getLeft();
|
||||||
|
|
||||||
getWidget(effectBox, "EffectBox");
|
getWidget(effectBox, "EffectBox");
|
||||||
getWidget(effect1, "Effect1");
|
getWidget(effect1, "Effect1");
|
||||||
|
effectBoxBaseRight = effectBox->getRight();
|
||||||
|
|
||||||
|
getWidget(minimapBox, "MiniMapBox");
|
||||||
|
minimapBoxBaseRight = minimapBox->getRight();
|
||||||
getWidget(minimap, "MiniMap");
|
getWidget(minimap, "MiniMap");
|
||||||
getWidget(compass, "Compass");
|
getWidget(compass, "Compass");
|
||||||
|
|
||||||
getWidget(crosshair, "Crosshair");
|
getWidget(crosshair, "Crosshair");
|
||||||
|
|
||||||
if ( fpsLevel == 2 ){
|
setFpsLevel(fpsLevel);
|
||||||
getWidget(fpsbox, "FPSBoxAdv");
|
|
||||||
fpsbox->setVisible(true);
|
|
||||||
getWidget(fpscounter, "FPSCounterAdv");
|
|
||||||
}else if ( fpsLevel == 1 ){
|
|
||||||
getWidget(fpsbox, "FPSBox");
|
|
||||||
fpsbox->setVisible(true);
|
|
||||||
getWidget(fpscounter, "FPSCounter");
|
|
||||||
}else{
|
|
||||||
getWidget(fpscounter, "FPSCounter");
|
|
||||||
}
|
|
||||||
getWidget(trianglecounter, "TriangleCounter");
|
getWidget(trianglecounter, "TriangleCounter");
|
||||||
getWidget(batchcounter, "BatchCounter");
|
getWidget(batchcounter, "BatchCounter");
|
||||||
|
|
||||||
|
@ -65,6 +86,28 @@ HUD::HUD(int width, int height, int fpsLevel)
|
||||||
LocalMapBase::init(minimap, this);
|
LocalMapBase::init(minimap, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HUD::setFpsLevel(int level)
|
||||||
|
{
|
||||||
|
MyGUI::Widget* fps;
|
||||||
|
getWidget(fps, "FPSBoxAdv");
|
||||||
|
fps->setVisible(false);
|
||||||
|
getWidget(fps, "FPSBox");
|
||||||
|
fps->setVisible(false);
|
||||||
|
|
||||||
|
if (level == 2)
|
||||||
|
{
|
||||||
|
getWidget(fpsbox, "FPSBoxAdv");
|
||||||
|
fpsbox->setVisible(true);
|
||||||
|
getWidget(fpscounter, "FPSCounterAdv");
|
||||||
|
}
|
||||||
|
else if (level == 1)
|
||||||
|
{
|
||||||
|
getWidget(fpsbox, "FPSBox");
|
||||||
|
fpsbox->setVisible(true);
|
||||||
|
getWidget(fpscounter, "FPSCounter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HUD::setFPS(float fps)
|
void HUD::setFPS(float fps)
|
||||||
{
|
{
|
||||||
fpscounter->setCaption(boost::lexical_cast<std::string>((int)fps));
|
fpscounter->setCaption(boost::lexical_cast<std::string>((int)fps));
|
||||||
|
@ -147,15 +190,21 @@ void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<int>& v
|
||||||
|
|
||||||
void HUD::setPlayerDir(const float x, const float y)
|
void HUD::setPlayerDir(const float x, const float y)
|
||||||
{
|
{
|
||||||
|
if (!minimapBox->getVisible() || (x == mLastPositionX && y == mLastPositionY)) return;
|
||||||
|
|
||||||
MyGUI::ISubWidget* main = compass->getSubWidgetMain();
|
MyGUI::ISubWidget* main = compass->getSubWidgetMain();
|
||||||
MyGUI::RotatingSkin* rotatingSubskin = main->castType<MyGUI::RotatingSkin>();
|
MyGUI::RotatingSkin* rotatingSubskin = main->castType<MyGUI::RotatingSkin>();
|
||||||
rotatingSubskin->setCenter(MyGUI::IntPoint(16,16));
|
rotatingSubskin->setCenter(MyGUI::IntPoint(16,16));
|
||||||
float angle = std::atan2(x,y);
|
float angle = std::atan2(x,y);
|
||||||
rotatingSubskin->setAngle(angle);
|
rotatingSubskin->setAngle(angle);
|
||||||
|
mLastPositionX = x;
|
||||||
|
mLastPositionY = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HUD::setPlayerPos(const float x, const float y)
|
void HUD::setPlayerPos(const float x, const float y)
|
||||||
{
|
{
|
||||||
|
if (!minimapBox->getVisible() || (x == mLastDirectionX && y == mLastDirectionY)) return;
|
||||||
|
|
||||||
MyGUI::IntSize size = minimap->getCanvasSize();
|
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::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::IntCoord viewsize = minimap->getCoord();
|
||||||
|
@ -163,96 +212,55 @@ void HUD::setPlayerPos(const float x, const float y)
|
||||||
|
|
||||||
minimap->setViewOffset(pos);
|
minimap->setViewOffset(pos);
|
||||||
compass->setPosition(MyGUI::IntPoint(x*512-16, y*512-16));
|
compass->setPosition(MyGUI::IntPoint(x*512-16, y*512-16));
|
||||||
|
|
||||||
|
mLastDirectionX = x;
|
||||||
|
mLastDirectionY = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapWindow::MapWindow()
|
void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible)
|
||||||
: Layout("openmw_map_window_layout.xml"), mGlobal(false)
|
|
||||||
{
|
{
|
||||||
setCoord(500,0,320,300);
|
int weapDx = 0, spellDx = 0;
|
||||||
setText("WorldButton", "World");
|
if (!hmsVisible)
|
||||||
setImage("Compass", "textures\\compass.dds");
|
spellDx = weapDx = weapBoxBaseLeft - hmsBaseLeft;
|
||||||
|
|
||||||
// Obviously you should override this later on
|
if (!weapVisible)
|
||||||
setCellName("No Cell Loaded");
|
spellDx -= spellBoxBaseLeft - weapBoxBaseLeft;
|
||||||
|
|
||||||
getWidget(mLocalMap, "LocalMap");
|
health->setVisible(hmsVisible);
|
||||||
getWidget(mGlobalMap, "GlobalMap");
|
stamina->setVisible(hmsVisible);
|
||||||
getWidget(mPlayerArrow, "Compass");
|
magicka->setVisible(hmsVisible);
|
||||||
|
weapBox->setPosition(weapBoxBaseLeft - weapDx, weapBox->getTop());
|
||||||
getWidget(mButton, "WorldButton");
|
weapBox->setVisible(weapVisible);
|
||||||
mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked);
|
spellBox->setPosition(spellBoxBaseLeft - spellDx, spellBox->getTop());
|
||||||
|
spellBox->setVisible(spellVisible);
|
||||||
MyGUI::Button* eventbox;
|
|
||||||
getWidget(eventbox, "EventBox");
|
|
||||||
eventbox->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
|
||||||
eventbox->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
|
||||||
|
|
||||||
LocalMapBase::init(mLocalMap, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWindow::setVisible(bool b)
|
void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible)
|
||||||
{
|
{
|
||||||
mMainWidget->setVisible(b);
|
// effect box can have variable width -> variable left coordinate
|
||||||
if (b)
|
int effectsDx = 0;
|
||||||
mVisible = true;
|
if (!minimapBoxVisible)
|
||||||
else
|
effectsDx = minimapBoxBaseRight - effectBoxBaseRight;
|
||||||
mVisible = false;
|
|
||||||
|
minimapBox->setVisible(minimapBoxVisible);
|
||||||
|
effectBox->setPosition(effectBoxBaseRight - effectBox->getWidth() + effectsDx, effectBox->getTop());
|
||||||
|
effectBox->setVisible(effectBoxVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWindow::setCellName(const std::string& cellName)
|
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)
|
||||||
{
|
{
|
||||||
static_cast<MyGUI::Window*>(mMainWidget)->setCaption(cellName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapWindow::setPlayerPos(const float x, const float y)
|
|
||||||
{
|
|
||||||
if (mGlobal || mVisible) return;
|
|
||||||
MyGUI::IntSize size = mLocalMap->getCanvasSize();
|
|
||||||
MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height);
|
|
||||||
MyGUI::IntCoord viewsize = mLocalMap->getCoord();
|
|
||||||
MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top);
|
|
||||||
mLocalMap->setViewOffset(pos);
|
|
||||||
|
|
||||||
mPlayerArrow->setPosition(MyGUI::IntPoint(x*512-16, y*512-16));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapWindow::setPlayerDir(const float x, const float y)
|
|
||||||
{
|
|
||||||
if (!mVisible) return;
|
|
||||||
MyGUI::ISubWidget* main = mPlayerArrow->getSubWidgetMain();
|
|
||||||
MyGUI::RotatingSkin* rotatingSubskin = main->castType<MyGUI::RotatingSkin>();
|
|
||||||
rotatingSubskin->setCenter(MyGUI::IntPoint(16,16));
|
|
||||||
float angle = std::atan2(x,y);
|
|
||||||
rotatingSubskin->setAngle(angle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
|
||||||
{
|
|
||||||
if (_id!=MyGUI::MouseButton::Left) return;
|
|
||||||
if (!mGlobal)
|
|
||||||
mLastDragPos = MyGUI::IntPoint(_left, _top);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
|
||||||
{
|
|
||||||
if (_id!=MyGUI::MouseButton::Left) return;
|
|
||||||
|
|
||||||
if (!mGlobal)
|
|
||||||
{
|
|
||||||
MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos;
|
|
||||||
mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff );
|
|
||||||
|
|
||||||
mLastDragPos = MyGUI::IntPoint(_left, _top);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender)
|
|
||||||
{
|
|
||||||
mGlobal = !mGlobal;
|
|
||||||
mGlobalMap->setVisible(mGlobal);
|
|
||||||
mLocalMap->setVisible(!mGlobal);
|
|
||||||
|
|
||||||
mButton->setCaption( mGlobal ? "Local" : "World" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout)
|
void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout)
|
||||||
|
@ -267,6 +275,32 @@ void LocalMapBase::setCellPrefix(const std::string& prefix)
|
||||||
mChanged = true;
|
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)
|
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
|
if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell
|
||||||
|
@ -282,23 +316,17 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
|
||||||
|
|
||||||
MyGUI::ImageBox* box;
|
MyGUI::ImageBox* box;
|
||||||
mLayout->getWidget(box, name);
|
mLayout->getWidget(box, name);
|
||||||
MyGUI::ImageBox* fog;
|
|
||||||
mLayout->getWidget(fog, name+"_fog");
|
|
||||||
|
|
||||||
if (MyGUI::RenderManager::getInstance().getTexture(image) != 0)
|
if (MyGUI::RenderManager::getInstance().getTexture(image) != 0)
|
||||||
box->setImageTexture(image);
|
box->setImageTexture(image);
|
||||||
else
|
else
|
||||||
box->setImageTexture("black.png");
|
box->setImageTexture("black.png");
|
||||||
|
|
||||||
if (MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0)
|
|
||||||
fog->setImageTexture(image+"_fog");
|
|
||||||
else
|
|
||||||
fog->setImageTexture("black.png");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mInterior = interior;
|
mInterior = interior;
|
||||||
mCurX = x;
|
mCurX = x;
|
||||||
mCurY = y;
|
mCurY = y;
|
||||||
mChanged = false;
|
mChanged = false;
|
||||||
|
applyFogOfWar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,19 +34,30 @@ namespace MWGui
|
||||||
class LocalMapBase
|
class LocalMapBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
LocalMapBase();
|
||||||
void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout);
|
void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout);
|
||||||
|
|
||||||
void setCellPrefix(const std::string& prefix);
|
void setCellPrefix(const std::string& prefix);
|
||||||
void setActiveCell(const int x, const int y, bool interior=false);
|
void setActiveCell(const int x, const int y, bool interior=false);
|
||||||
|
|
||||||
|
void toggleFogOfWar();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int mCurX, mCurY;
|
int mCurX, mCurY;
|
||||||
bool mInterior;
|
bool mInterior;
|
||||||
MyGUI::ScrollView* mLocalMap;
|
MyGUI::ScrollView* mLocalMap;
|
||||||
std::string mPrefix;
|
std::string mPrefix;
|
||||||
bool mChanged;
|
bool mChanged;
|
||||||
|
bool mFogOfWar;
|
||||||
|
|
||||||
|
void applyFogOfWar();
|
||||||
|
|
||||||
OEngine::GUI::Layout* mLayout;
|
OEngine::GUI::Layout* mLayout;
|
||||||
|
|
||||||
|
float mLastPositionX;
|
||||||
|
float mLastPositionY;
|
||||||
|
float mLastDirectionX;
|
||||||
|
float mLastDirectionY;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HUD : public OEngine::GUI::Layout, public LocalMapBase
|
class HUD : public OEngine::GUI::Layout, public LocalMapBase
|
||||||
|
@ -65,11 +76,15 @@ namespace MWGui
|
||||||
void setBatchCount(size_t count);
|
void setBatchCount(size_t count);
|
||||||
void setPlayerDir(const float x, const float y);
|
void setPlayerDir(const float x, const float y);
|
||||||
void setPlayerPos(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);
|
||||||
|
void setFpsLevel(const int level);
|
||||||
|
|
||||||
MyGUI::ProgressPtr health, magicka, stamina;
|
MyGUI::ProgressPtr health, magicka, stamina;
|
||||||
|
MyGUI::Widget *weapBox, *spellBox;
|
||||||
MyGUI::ImageBox *weapImage, *spellImage;
|
MyGUI::ImageBox *weapImage, *spellImage;
|
||||||
MyGUI::ProgressPtr weapStatus, spellStatus;
|
MyGUI::ProgressPtr weapStatus, spellStatus;
|
||||||
MyGUI::WidgetPtr effectBox;
|
MyGUI::Widget *effectBox, *minimapBox;
|
||||||
MyGUI::ImageBox* effect1;
|
MyGUI::ImageBox* effect1;
|
||||||
MyGUI::ScrollView* minimap;
|
MyGUI::ScrollView* minimap;
|
||||||
MyGUI::ImageBox* compass;
|
MyGUI::ImageBox* compass;
|
||||||
|
@ -79,29 +94,12 @@ namespace MWGui
|
||||||
MyGUI::TextBox* fpscounter;
|
MyGUI::TextBox* fpscounter;
|
||||||
MyGUI::TextBox* trianglecounter;
|
MyGUI::TextBox* trianglecounter;
|
||||||
MyGUI::TextBox* batchcounter;
|
MyGUI::TextBox* batchcounter;
|
||||||
};
|
|
||||||
|
|
||||||
class MapWindow : public OEngine::GUI::Layout, public LocalMapBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MapWindow();
|
|
||||||
|
|
||||||
void setVisible(bool b);
|
|
||||||
void setPlayerPos(const float x, const float y);
|
|
||||||
void setPlayerDir(const float x, const float y);
|
|
||||||
void setCellName(const std::string& cellName);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
// bottom left elements
|
||||||
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft;
|
||||||
void onWorldButtonClicked(MyGUI::Widget* _sender);
|
// bottom right elements
|
||||||
|
int minimapBoxBaseRight, effectBoxBaseRight;
|
||||||
MyGUI::ScrollView* mGlobalMap;
|
|
||||||
MyGUI::ImageBox* mPlayerArrow;
|
|
||||||
MyGUI::Button* mButton;
|
|
||||||
MyGUI::IntPoint mLastDragPos;
|
|
||||||
bool mVisible;
|
|
||||||
bool mGlobal;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MainMenu : public OEngine::GUI::Layout
|
class MainMenu : public OEngine::GUI::Layout
|
||||||
|
|
106
apps/openmw/mwgui/map_window.cpp
Normal file
106
apps/openmw/mwgui/map_window.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
34
apps/openmw/mwgui/map_window.hpp
Normal file
34
apps/openmw/mwgui/map_window.hpp
Normal file
|
@ -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
|
|
@ -7,6 +7,7 @@
|
||||||
#include "window_base.hpp"
|
#include "window_base.hpp"
|
||||||
#include "window_manager.hpp"
|
#include "window_manager.hpp"
|
||||||
|
|
||||||
|
#undef MessageBox
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,10 +12,23 @@ using namespace MWGui;
|
||||||
const int StatsWindow::lineHeight = 18;
|
const int StatsWindow::lineHeight = 18;
|
||||||
|
|
||||||
StatsWindow::StatsWindow (WindowManager& parWindowManager)
|
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)
|
, lastPos(0)
|
||||||
|
, clientHeight(0)
|
||||||
|
, majorSkills()
|
||||||
|
, minorSkills()
|
||||||
|
, miscSkills()
|
||||||
|
, skillValues()
|
||||||
|
, skillWidgetMap()
|
||||||
|
, factionWidgetMap()
|
||||||
|
, factions()
|
||||||
|
, birthSignId()
|
||||||
, reputation(0)
|
, reputation(0)
|
||||||
, bounty(0)
|
, bounty(0)
|
||||||
|
, skillWidgets()
|
||||||
{
|
{
|
||||||
setCoord(0,0,498, 342);
|
setCoord(0,0,498, 342);
|
||||||
|
|
||||||
|
@ -368,3 +381,8 @@ void StatsWindow::updateScroller()
|
||||||
skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0));
|
skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0));
|
||||||
skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0));
|
skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatsWindow::onPinToggled()
|
||||||
|
{
|
||||||
|
mWindowManager.setHMSVisibility(!mPinned);
|
||||||
|
}
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "../mwmechanics/stat.hpp"
|
#include "../mwmechanics/stat.hpp"
|
||||||
#include "window_base.hpp"
|
#include "window_pinnable_base.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class WindowManager;
|
class WindowManager;
|
||||||
|
|
||||||
class StatsWindow : public WindowBase
|
class StatsWindow : public WindowPinnableBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::pair<std::string, int> Faction;
|
typedef std::pair<std::string, int> Faction;
|
||||||
|
@ -74,6 +74,9 @@ namespace MWGui
|
||||||
std::string birthSignId;
|
std::string birthSignId;
|
||||||
int reputation, bounty;
|
int reputation, bounty;
|
||||||
std::vector<MyGUI::WidgetPtr> skillWidgets; //< Skills and other information
|
std::vector<MyGUI::WidgetPtr> skillWidgets; //< Skills and other information
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void onPinToggled();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
#include "../mwmechanics/stat.hpp"
|
#include "../mwmechanics/stat.hpp"
|
||||||
|
|
||||||
|
#undef MYGUI_EXPORT
|
||||||
|
#define MYGUI_EXPORT
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file contains various custom widgets used in OpenMW.
|
This file contains various custom widgets used in OpenMW.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "review.hpp"
|
#include "review.hpp"
|
||||||
#include "dialogue.hpp"
|
#include "dialogue.hpp"
|
||||||
#include "dialogue_history.hpp"
|
#include "dialogue_history.hpp"
|
||||||
|
#include "map_window.hpp"
|
||||||
#include "stats_window.hpp"
|
#include "stats_window.hpp"
|
||||||
#include "messagebox.hpp"
|
#include "messagebox.hpp"
|
||||||
#include "container.hpp"
|
#include "container.hpp"
|
||||||
|
@ -15,6 +16,8 @@
|
||||||
#include "journalwindow.hpp"
|
#include "journalwindow.hpp"
|
||||||
#include "charactercreation.hpp"
|
#include "charactercreation.hpp"
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
@ -23,15 +26,40 @@ using namespace MWGui;
|
||||||
|
|
||||||
WindowManager::WindowManager(MWWorld::Environment& environment,
|
WindowManager::WindowManager(MWWorld::Environment& environment,
|
||||||
const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath)
|
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)
|
, dialogueWindow(nullptr)
|
||||||
|
, mCharGen(NULL)
|
||||||
|
, playerClass()
|
||||||
|
, playerName()
|
||||||
|
, playerRaceId()
|
||||||
|
, playerBirthSignId()
|
||||||
|
, playerAttributes()
|
||||||
|
, playerMajorSkills()
|
||||||
|
, playerMinorSkills()
|
||||||
|
, playerSkillValues()
|
||||||
|
, playerHealth()
|
||||||
|
, playerMagicka()
|
||||||
|
, playerFatigue()
|
||||||
|
, gui(NULL)
|
||||||
, mode(GM_Game)
|
, mode(GM_Game)
|
||||||
, nextMode(GM_Game)
|
, nextMode(GM_Game)
|
||||||
, needModeChange(false)
|
, needModeChange(false)
|
||||||
|
, garbageDialogs()
|
||||||
, shown(GW_ALL)
|
, shown(GW_ALL)
|
||||||
, allowed(newGame ? GW_None : GW_ALL)
|
, allowed(newGame ? GW_None : GW_ALL)
|
||||||
|
, showFPSLevel(fpsLevel)
|
||||||
|
, mFPS(0.0f)
|
||||||
|
, mTriangleCount(0)
|
||||||
|
, mBatchCount(0)
|
||||||
{
|
{
|
||||||
showFPSLevel = fpsLevel;
|
|
||||||
|
|
||||||
// Set up the GUI system
|
// Set up the GUI system
|
||||||
mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath);
|
mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath);
|
||||||
|
@ -47,7 +75,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment,
|
||||||
|
|
||||||
hud = new HUD(w,h, showFPSLevel);
|
hud = new HUD(w,h, showFPSLevel);
|
||||||
menu = new MainMenu(w,h);
|
menu = new MainMenu(w,h);
|
||||||
map = new MapWindow();
|
map = new MapWindow(*this);
|
||||||
stats = new StatsWindow(*this);
|
stats = new StatsWindow(*this);
|
||||||
console = new Console(w,h, environment, extensions);
|
console = new Console(w,h, environment, extensions);
|
||||||
mJournal = new JournalWindow(*this);
|
mJournal = new JournalWindow(*this);
|
||||||
|
@ -157,71 +185,58 @@ void WindowManager::updateVisible()
|
||||||
// Mouse is visible whenever we're not in game mode
|
// Mouse is visible whenever we're not in game mode
|
||||||
MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
|
MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
|
||||||
|
|
||||||
// If in game mode, don't show anything.
|
switch(mode) {
|
||||||
if(mode == GM_Game) //Use a switch/case structure
|
case GM_Game:
|
||||||
{
|
// If in game mode, don't show anything.
|
||||||
return;
|
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;
|
||||||
|
|
||||||
if(mode == GM_MainMenu)
|
// Show the windows we want
|
||||||
{
|
map -> setVisible( (eff & GW_Map) != 0 );
|
||||||
// Enable the main menu
|
stats -> setVisible( (eff & GW_Stats) != 0 );
|
||||||
menu->setVisible(true);
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode == GM_Journal)
|
|
||||||
{
|
|
||||||
mJournal->setVisible(true);
|
|
||||||
mJournal->open();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int>& value)
|
||||||
|
@ -348,7 +363,6 @@ void WindowManager::updateSkillArea()
|
||||||
|
|
||||||
void WindowManager::removeDialog(OEngine::GUI::Layout*dialog)
|
void WindowManager::removeDialog(OEngine::GUI::Layout*dialog)
|
||||||
{
|
{
|
||||||
std::cout << "dialogue a la poubelle";
|
|
||||||
assert(dialog);
|
assert(dialog);
|
||||||
if (!dialog)
|
if (!dialog)
|
||||||
return;
|
return;
|
||||||
|
@ -446,3 +460,27 @@ void WindowManager::setPlayerDir(const float x, const float y)
|
||||||
map->setPlayerDir(x,y);
|
map->setPlayerDir(x,y);
|
||||||
hud->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();
|
||||||
|
}
|
||||||
|
|
||||||
|
int WindowManager::toggleFps()
|
||||||
|
{
|
||||||
|
showFPSLevel = (showFPSLevel+1)%3;
|
||||||
|
hud->setFpsLevel(showFPSLevel);
|
||||||
|
Settings::Manager::setInt("fps", "HUD", showFPSLevel);
|
||||||
|
return showFPSLevel;
|
||||||
|
}
|
||||||
|
|
|
@ -158,10 +158,20 @@ namespace MWGui
|
||||||
void changeCell(MWWorld::Ptr::CellStore* cell); ///< change the active cell
|
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 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 setPlayerDir(const float x, const float y); ///< set player view direction in map space
|
||||||
|
|
||||||
|
void toggleFogOfWar();
|
||||||
|
|
||||||
|
int toggleFps();
|
||||||
|
///< toggle fps display @return resulting fps level
|
||||||
|
|
||||||
void setInteriorMapTexture(const int x, const int y);
|
void setInteriorMapTexture(const int x, const int y);
|
||||||
///< set the index of the map texture that should be used (for interiors)
|
///< 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>
|
template<typename T>
|
||||||
void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr.
|
void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr.
|
||||||
void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted.
|
void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted.
|
||||||
|
|
33
apps/openmw/mwgui/window_pinnable_base.cpp
Normal file
33
apps/openmw/mwgui/window_pinnable_base.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
28
apps/openmw/mwgui/window_pinnable_base.hpp
Normal file
28
apps/openmw/mwgui/window_pinnable_base.hpp
Normal file
|
@ -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
|
||||||
|
|
|
@ -65,12 +65,16 @@ namespace MWInput
|
||||||
A_QuickLoad,
|
A_QuickLoad,
|
||||||
A_QuickMenu,
|
A_QuickMenu,
|
||||||
A_GameMenu,
|
A_GameMenu,
|
||||||
|
A_ToggleWeapon,
|
||||||
|
A_ToggleSpell,
|
||||||
|
|
||||||
|
A_ToggleFps, // Toggle FPS display (this is temporary)
|
||||||
|
|
||||||
A_LAST // Marker for the last item
|
A_LAST // Marker for the last item
|
||||||
};
|
};
|
||||||
|
|
||||||
// Class that handles all input and key bindings for OpenMW
|
// Class that handles all input and key bindings for OpenMW
|
||||||
class InputImpl : public Ogre::FrameListener
|
class InputImpl
|
||||||
{
|
{
|
||||||
OEngine::Input::DispatcherPtr disp;
|
OEngine::Input::DispatcherPtr disp;
|
||||||
OEngine::Render::OgreRenderer &ogre;
|
OEngine::Render::OgreRenderer &ogre;
|
||||||
|
@ -86,6 +90,43 @@ namespace MWInput
|
||||||
|
|
||||||
/* InputImpl Methods */
|
/* InputImpl Methods */
|
||||||
|
|
||||||
|
void toggleFps()
|
||||||
|
{
|
||||||
|
windows.toggleFps();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleSpell()
|
||||||
|
{
|
||||||
|
DrawState state = player.getDrawState();
|
||||||
|
if(state == DrawState_Weapon || state == DrawState_Nothing)
|
||||||
|
{
|
||||||
|
player.setDrawState(DrawState_Spell);
|
||||||
|
std::cout << "Player has now readied his hands for spellcasting!\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player.setDrawState(DrawState_Nothing);
|
||||||
|
std::cout << "Player does not have any kind of attack ready now.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleWeapon()
|
||||||
|
{
|
||||||
|
DrawState state = player.getDrawState();
|
||||||
|
if(state == DrawState_Spell || state == DrawState_Nothing)
|
||||||
|
{
|
||||||
|
player.setDrawState(DrawState_Weapon);
|
||||||
|
std::cout << "Player is now drawing his weapon.\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player.setDrawState(DrawState_Nothing);
|
||||||
|
std::cout << "Player does not have any kind of attack ready now.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void screenshot()
|
void screenshot()
|
||||||
{
|
{
|
||||||
mEngine.screenshot();
|
mEngine.screenshot();
|
||||||
|
@ -197,11 +238,14 @@ namespace MWInput
|
||||||
"Auto Move");
|
"Auto Move");
|
||||||
disp->funcs.bind(A_ToggleWalk, boost::bind(&InputImpl::toggleWalking, this),
|
disp->funcs.bind(A_ToggleWalk, boost::bind(&InputImpl::toggleWalking, this),
|
||||||
"Toggle Walk/Run");
|
"Toggle Walk/Run");
|
||||||
|
disp->funcs.bind(A_ToggleWeapon,boost::bind(&InputImpl::toggleWeapon,this),
|
||||||
|
"Draw Weapon");
|
||||||
|
disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this),
|
||||||
|
"Ready hands");
|
||||||
|
disp->funcs.bind(A_ToggleFps, boost::bind(&InputImpl::toggleFps, this),
|
||||||
|
"Toggle FPS display");
|
||||||
// Add the exit listener
|
// Add the exit listener
|
||||||
ogre.getRoot()->addFrameListener(&exit);
|
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
|
// Set up the mouse handler and tell it about the player camera
|
||||||
mouse = MouseLookEventPtr(new MouseLookEvent(player.getRenderer()->getCamera()));
|
mouse = MouseLookEventPtr(new MouseLookEvent(player.getRenderer()->getCamera()));
|
||||||
|
@ -244,6 +288,9 @@ namespace MWInput
|
||||||
disp->bind(A_AutoMove, KC_Z);
|
disp->bind(A_AutoMove, KC_Z);
|
||||||
disp->bind(A_ToggleSneak, KC_X);
|
disp->bind(A_ToggleSneak, KC_X);
|
||||||
disp->bind(A_ToggleWalk, KC_C);
|
disp->bind(A_ToggleWalk, KC_C);
|
||||||
|
disp->bind(A_ToggleWeapon,KC_F);
|
||||||
|
disp->bind(A_ToggleSpell,KC_R);
|
||||||
|
disp->bind(A_ToggleFps, KC_F10);
|
||||||
|
|
||||||
// Key bindings for polled keys
|
// Key bindings for polled keys
|
||||||
// NOTE: These keys are constantly being polled. Only add keys that must be checked each frame.
|
// NOTE: These keys are constantly being polled. Only add keys that must be checked each frame.
|
||||||
|
@ -262,7 +309,7 @@ namespace MWInput
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: Used to check for movement keys
|
//NOTE: Used to check for movement keys
|
||||||
bool frameRenderingQueued (const Ogre::FrameEvent &evt)
|
void update ()
|
||||||
{
|
{
|
||||||
// Tell OIS to handle all input events
|
// Tell OIS to handle all input events
|
||||||
input.capture();
|
input.capture();
|
||||||
|
@ -276,7 +323,7 @@ namespace MWInput
|
||||||
windows.update();
|
windows.update();
|
||||||
|
|
||||||
// Disable movement in Gui mode
|
// Disable movement in Gui mode
|
||||||
if (windows.isGuiMode()) return true;
|
if (windows.isGuiMode()) return;
|
||||||
|
|
||||||
// Configure player movement according to keyboard input. Actual movement will
|
// Configure player movement according to keyboard input. Actual movement will
|
||||||
// be done in the physics system.
|
// be done in the physics system.
|
||||||
|
@ -305,8 +352,6 @@ namespace MWInput
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
player.setForwardBackward (0);
|
player.setForwardBackward (0);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch between gui modes. Besides controlling the Gui windows
|
// Switch between gui modes. Besides controlling the Gui windows
|
||||||
|
@ -358,4 +403,9 @@ namespace MWInput
|
||||||
{
|
{
|
||||||
impl->setGuiMode(mode);
|
impl->setGuiMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWInputManager::update()
|
||||||
|
{
|
||||||
|
impl->update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,8 @@ namespace MWInput
|
||||||
OMW::Engine& engine);
|
OMW::Engine& engine);
|
||||||
~MWInputManager();
|
~MWInputManager();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
void setGuiMode(MWGui::GuiMode mode);
|
void setGuiMode(MWGui::GuiMode mode);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
77
apps/openmw/mwmechanics/actors.cpp
Normal file
77
apps/openmw/mwmechanics/actors.cpp
Normal file
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
apps/openmw/mwmechanics/actors.hpp
Normal file
51
apps/openmw/mwmechanics/actors.hpp
Normal file
|
@ -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
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "stat.hpp"
|
#include "stat.hpp"
|
||||||
#include "magiceffects.hpp"
|
#include "magiceffects.hpp"
|
||||||
|
#include "spells.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -14,7 +15,7 @@ namespace MWMechanics
|
||||||
Stat<int> mAttributes[8];
|
Stat<int> mAttributes[8];
|
||||||
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
|
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
|
||||||
int mLevel;
|
int mLevel;
|
||||||
std::set<std::string> mAbilities;
|
Spells mSpells;
|
||||||
MagicEffects mMagicEffects;
|
MagicEffects mMagicEffects;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
13
apps/openmw/mwmechanics/drawstate.hpp
Normal file
13
apps/openmw/mwmechanics/drawstate.hpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef GAME_MWMECHANICS_DRAWSTATE_H
|
||||||
|
#define GAME_MWMECHANICS_DRAWSTATE_H
|
||||||
|
|
||||||
|
#undef DrawState
|
||||||
|
|
||||||
|
enum DrawState
|
||||||
|
{
|
||||||
|
DrawState_Weapon = 0,
|
||||||
|
DrawState_Spell = 1,
|
||||||
|
DrawState_Nothing = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,7 +23,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
// reset
|
// reset
|
||||||
creatureStats.mLevel = player->npdt52.level;
|
creatureStats.mLevel = player->npdt52.level;
|
||||||
creatureStats.mAbilities.clear();
|
creatureStats.mSpells.clear();
|
||||||
creatureStats.mMagicEffects = MagicEffects();
|
creatureStats.mMagicEffects = MagicEffects();
|
||||||
|
|
||||||
for (int i=0; i<27; ++i)
|
for (int i=0; i<27; ++i)
|
||||||
|
@ -71,7 +71,7 @@ namespace MWMechanics
|
||||||
for (std::vector<std::string>::const_iterator iter (race->powers.list.begin());
|
for (std::vector<std::string>::const_iterator iter (race->powers.list.begin());
|
||||||
iter!=race->powers.list.end(); ++iter)
|
iter!=race->powers.list.end(); ++iter)
|
||||||
{
|
{
|
||||||
insertSpell (*iter, ptr);
|
creatureStats.mSpells.add (*iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ namespace MWMechanics
|
||||||
for (std::vector<std::string>::const_iterator iter (sign->powers.list.begin());
|
for (std::vector<std::string>::const_iterator iter (sign->powers.list.begin());
|
||||||
iter!=sign->powers.list.end(); ++iter)
|
iter!=sign->powers.list.end(); ++iter)
|
||||||
{
|
{
|
||||||
insertSpell (*iter, ptr);
|
creatureStats.mSpells.add (*iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,59 +159,14 @@ namespace MWMechanics
|
||||||
creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified());
|
creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::insertSpell (const std::string& id, MWWorld::Ptr& creature)
|
|
||||||
{
|
|
||||||
MWMechanics::CreatureStats& creatureStats =
|
|
||||||
MWWorld::Class::get (creature).getCreatureStats (creature);
|
|
||||||
|
|
||||||
const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (id);
|
|
||||||
|
|
||||||
switch (spell->data.type)
|
|
||||||
{
|
|
||||||
case ESM::Spell::ST_Ability:
|
|
||||||
|
|
||||||
if (creatureStats.mAbilities.find (id)==creatureStats.mAbilities.end())
|
|
||||||
{
|
|
||||||
creatureStats.mAbilities.insert (id);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TODO ST_SPELL, ST_Blight, ST_Disease, ST_Curse, ST_Power
|
|
||||||
|
|
||||||
default:
|
|
||||||
|
|
||||||
std::cout
|
|
||||||
<< "adding unsupported spell type (" << spell->data.type
|
|
||||||
<< ") to creature: " << id << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature)
|
void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature)
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& creatureStats =
|
MWMechanics::CreatureStats& creatureStats =
|
||||||
MWWorld::Class::get (creature).getCreatureStats (creature);
|
MWWorld::Class::get (creature).getCreatureStats (creature);
|
||||||
|
|
||||||
MagicEffects now;
|
MagicEffects now = creatureStats.mSpells.getMagicEffects (mEnvironment);
|
||||||
|
|
||||||
for (std::set<std::string>::const_iterator iter (creatureStats.mAbilities.begin());
|
/// \todo add effects from active spells and equipment
|
||||||
iter!=creatureStats.mAbilities.end(); ++iter)
|
|
||||||
{
|
|
||||||
const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (*iter);
|
|
||||||
|
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->effects.list.begin();
|
|
||||||
iter!=spell->effects.list.end(); ++iter)
|
|
||||||
{
|
|
||||||
if (iter->range==0) // self
|
|
||||||
{
|
|
||||||
EffectParam param;
|
|
||||||
param.mMagnitude = iter->magnMax; // TODO calculate magnitude
|
|
||||||
now.add (EffectKey (*iter), param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO add effects from other spell types, active spells and equipment
|
|
||||||
|
|
||||||
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now);
|
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now);
|
||||||
|
|
||||||
|
@ -222,14 +177,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
MechanicsManager::MechanicsManager (MWWorld::Environment& environment)
|
MechanicsManager::MechanicsManager (MWWorld::Environment& environment)
|
||||||
: mEnvironment (environment), mUpdatePlayer (true), mClassSelected (false),
|
: mEnvironment (environment), mUpdatePlayer (true), mClassSelected (false),
|
||||||
mRaceSelected (false)
|
mRaceSelected (false), mActors (environment)
|
||||||
{
|
{
|
||||||
buildPlayer();
|
buildPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::addActor (const MWWorld::Ptr& ptr)
|
void MechanicsManager::addActor (const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
mActors.insert (ptr);
|
mActors.addActor (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::removeActor (const MWWorld::Ptr& ptr)
|
void MechanicsManager::removeActor (const MWWorld::Ptr& ptr)
|
||||||
|
@ -237,7 +192,7 @@ namespace MWMechanics
|
||||||
if (ptr==mWatched)
|
if (ptr==mWatched)
|
||||||
mWatched = MWWorld::Ptr();
|
mWatched = MWWorld::Ptr();
|
||||||
|
|
||||||
mActors.erase (ptr);
|
mActors.removeActor (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore)
|
void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore)
|
||||||
|
@ -245,16 +200,7 @@ namespace MWMechanics
|
||||||
if (!mWatched.isEmpty() && mWatched.getCell()==cellStore)
|
if (!mWatched.isEmpty() && mWatched.getCell()==cellStore)
|
||||||
mWatched = MWWorld::Ptr();
|
mWatched = MWWorld::Ptr();
|
||||||
|
|
||||||
std::set<MWWorld::Ptr>::iterator iter = mActors.begin();
|
mActors.dropActors (cellStore);
|
||||||
|
|
||||||
while (iter!=mActors.end())
|
|
||||||
if (iter->getCell()==cellStore)
|
|
||||||
{
|
|
||||||
//std::cout << "Erasing an actor";
|
|
||||||
mActors.erase (iter++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::watchActor (const MWWorld::Ptr& ptr)
|
void MechanicsManager::watchActor (const MWWorld::Ptr& ptr)
|
||||||
|
@ -262,7 +208,8 @@ namespace MWMechanics
|
||||||
mWatched = ptr;
|
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())
|
if (!mWatched.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -345,14 +292,7 @@ namespace MWMechanics
|
||||||
mEnvironment.mWindowManager->configureSkills (majorSkills, minorSkills);
|
mEnvironment.mWindowManager->configureSkills (majorSkills, minorSkills);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end();
|
mActors.update (movement, duration, paused);
|
||||||
++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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::setPlayerName (const std::string& name)
|
void MechanicsManager::setPlayerName (const std::string& name)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef GAME_MWMECHANICS_MECHANICSMANAGER_H
|
#ifndef GAME_MWMECHANICS_MECHANICSMANAGER_H
|
||||||
#define GAME_MWMECHANICS_MECHANICSMANAGER_H
|
#define GAME_MWMECHANICS_MECHANICSMANAGER_H
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -9,6 +8,7 @@
|
||||||
|
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
|
#include "actors.hpp"
|
||||||
|
|
||||||
namespace Ogre
|
namespace Ogre
|
||||||
{
|
{
|
||||||
|
@ -25,20 +25,18 @@ namespace MWMechanics
|
||||||
class MechanicsManager
|
class MechanicsManager
|
||||||
{
|
{
|
||||||
MWWorld::Environment& mEnvironment;
|
MWWorld::Environment& mEnvironment;
|
||||||
std::set<MWWorld::Ptr> mActors;
|
|
||||||
MWWorld::Ptr mWatched;
|
MWWorld::Ptr mWatched;
|
||||||
CreatureStats mWatchedCreature;
|
CreatureStats mWatchedCreature;
|
||||||
NpcStats mWatchedNpc;
|
NpcStats mWatchedNpc;
|
||||||
bool mUpdatePlayer;
|
bool mUpdatePlayer;
|
||||||
bool mClassSelected;
|
bool mClassSelected;
|
||||||
bool mRaceSelected;
|
bool mRaceSelected;
|
||||||
|
Actors mActors;
|
||||||
|
|
||||||
void buildPlayer();
|
void buildPlayer();
|
||||||
///< build player according to stored class/race/birthsign information. Will
|
///< build player according to stored class/race/birthsign information. Will
|
||||||
/// default to the values of the ESM::NPC object, if no explicit information is given.
|
/// default to the values of the ESM::NPC object, if no explicit information is given.
|
||||||
|
|
||||||
void insertSpell (const std::string& id, MWWorld::Ptr& creature);
|
|
||||||
|
|
||||||
void adjustMagicEffects (MWWorld::Ptr& creature);
|
void adjustMagicEffects (MWWorld::Ptr& creature);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -60,8 +58,12 @@ namespace MWMechanics
|
||||||
///< On each update look for changes in a previously registered actor and update the
|
///< On each update look for changes in a previously registered actor and update the
|
||||||
/// GUI accordingly.
|
/// 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
|
///< 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);
|
void setPlayerName (const std::string& name);
|
||||||
///< Set player name.
|
///< Set player name.
|
||||||
|
|
|
@ -2,14 +2,19 @@
|
||||||
#define GAME_MWMECHANICS_NPCSTATS_H
|
#define GAME_MWMECHANICS_NPCSTATS_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include "stat.hpp"
|
#include "stat.hpp"
|
||||||
|
#include "drawstate.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Additional stats for NPCs
|
/// \brief Additional stats for NPCs
|
||||||
///
|
///
|
||||||
/// For non-NPC-specific stats, see the CreatureStats struct.
|
/// For non-NPC-specific stats, see the CreatureStats struct.
|
||||||
|
///
|
||||||
|
/// \note For technical reasons the spell list and the currently selected spell is also handled by
|
||||||
|
/// CreatureStats, even though they are actually NPC stats.
|
||||||
|
|
||||||
struct NpcStats
|
struct NpcStats
|
||||||
{
|
{
|
||||||
|
@ -24,9 +29,10 @@ namespace MWMechanics
|
||||||
bool mRun;
|
bool mRun;
|
||||||
bool mSneak;
|
bool mSneak;
|
||||||
bool mCombat;
|
bool mCombat;
|
||||||
|
DrawState mDrawState;
|
||||||
|
|
||||||
NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false),
|
NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false),
|
||||||
mCombat (false) {}
|
mCombat (false) , mDrawState(DrawState_Nothing) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
81
apps/openmw/mwmechanics/spells.cpp
Normal file
81
apps/openmw/mwmechanics/spells.cpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
#include "spells.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/loadspel.hpp>
|
||||||
|
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
|
#include "../mwworld/world.hpp"
|
||||||
|
|
||||||
|
#include "magiceffects.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
void Spells::addSpell (const ESM::Spell *spell, MagicEffects& effects) const
|
||||||
|
{
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->effects.list.begin();
|
||||||
|
iter!=spell->effects.list.end(); ++iter)
|
||||||
|
{
|
||||||
|
EffectParam param;
|
||||||
|
param.mMagnitude = iter->magnMax; /// \todo calculate magnitude
|
||||||
|
effects.add (EffectKey (*iter), param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spells::TIterator Spells::begin() const
|
||||||
|
{
|
||||||
|
return mSpells.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
Spells::TIterator Spells::end() const
|
||||||
|
{
|
||||||
|
return mSpells.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spells::add (const std::string& spellId)
|
||||||
|
{
|
||||||
|
if (std::find (mSpells.begin(), mSpells.end(), spellId)!=mSpells.end())
|
||||||
|
mSpells.push_back (spellId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spells::remove (const std::string& spellId)
|
||||||
|
{
|
||||||
|
TContainer::iterator iter = std::find (mSpells.begin(), mSpells.end(), spellId);
|
||||||
|
|
||||||
|
if (iter!=mSpells.end())
|
||||||
|
mSpells.erase (iter);
|
||||||
|
|
||||||
|
if (spellId==mSelectedSpell)
|
||||||
|
mSelectedSpell.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
MagicEffects Spells::getMagicEffects (const MWWorld::Environment& environment) const
|
||||||
|
{
|
||||||
|
MagicEffects effects;
|
||||||
|
|
||||||
|
for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::Spell *spell = environment.mWorld->getStore().spells.find (*iter);
|
||||||
|
|
||||||
|
if (spell->data.type==ESM::Spell::ST_Ability || spell->data.type==ESM::Spell::ST_Blight ||
|
||||||
|
spell->data.type==ESM::Spell::ST_Disease || spell->data.type==ESM::Spell::ST_Curse)
|
||||||
|
addSpell (spell, effects);
|
||||||
|
}
|
||||||
|
|
||||||
|
return effects;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spells::clear()
|
||||||
|
{
|
||||||
|
mSpells.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spells::setSelectedSpell (const std::string& spellId)
|
||||||
|
{
|
||||||
|
mSelectedSpell = spellId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string Spells::getSelectedSpell() const
|
||||||
|
{
|
||||||
|
return mSelectedSpell;
|
||||||
|
}
|
||||||
|
}
|
66
apps/openmw/mwmechanics/spells.hpp
Normal file
66
apps/openmw/mwmechanics/spells.hpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef GAME_MWMECHANICS_SPELLS_H
|
||||||
|
#define GAME_MWMECHANICS_SPELLS_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct Spell;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
struct Environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
class MagicEffects;
|
||||||
|
|
||||||
|
/// \brief Spell list
|
||||||
|
///
|
||||||
|
/// This class manages known spells as well as abilities, powers and permanent negative effects like
|
||||||
|
/// diseaes.
|
||||||
|
class Spells
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef std::vector<std::string> TContainer;
|
||||||
|
typedef TContainer::const_iterator TIterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<std::string> mSpells;
|
||||||
|
std::string mSelectedSpell;
|
||||||
|
|
||||||
|
void addSpell (const ESM::Spell *, MagicEffects& effects) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
TIterator begin() const;
|
||||||
|
|
||||||
|
TIterator end() const;
|
||||||
|
|
||||||
|
void add (const std::string& spell);
|
||||||
|
///< Adding a spell that is already listed in *this is a no-op.
|
||||||
|
|
||||||
|
void remove (const std::string& spell);
|
||||||
|
///< If the spell to be removed is the selected spell, the selected spell will be changed to
|
||||||
|
/// no spell (empty string).
|
||||||
|
|
||||||
|
MagicEffects getMagicEffects (const MWWorld::Environment& environment) const;
|
||||||
|
///< Return sum of magic effects resulting from abilities, blights, deseases and curses.
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
///< Remove all spells of al types.
|
||||||
|
|
||||||
|
void setSelectedSpell (const std::string& spellId);
|
||||||
|
///< This function does not verify, if the spell is available.
|
||||||
|
|
||||||
|
const std::string getSelectedSpell() const;
|
||||||
|
///< May return an empty string.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -8,6 +8,15 @@ using namespace Ogre;
|
||||||
using namespace MWRender;
|
using namespace MWRender;
|
||||||
using namespace NifOgre;
|
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){
|
void Actors::setMwRoot(Ogre::SceneNode* root){
|
||||||
mMwRoot = root;
|
mMwRoot = root;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +70,7 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr){
|
||||||
insertBegin(ptr, true, true);
|
insertBegin(ptr, true, true);
|
||||||
CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mEnvironment, mRend);
|
CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mEnvironment, mRend);
|
||||||
//mAllActors.insert(std::pair<MWWorld::Ptr, Animation*>(ptr,anim));
|
//mAllActors.insert(std::pair<MWWorld::Ptr, Animation*>(ptr,anim));
|
||||||
|
delete mAllActors[ptr];
|
||||||
mAllActors[ptr] = anim;
|
mAllActors[ptr] = anim;
|
||||||
//mAllActors.push_back(&anim);*/
|
//mAllActors.push_back(&anim);*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace MWRender{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Actors(OEngine::Render::OgreRenderer& _rend, MWWorld::Environment& _env): mRend(_rend), mEnvironment(_env){}
|
Actors(OEngine::Render::OgreRenderer& _rend, MWWorld::Environment& _env): mRend(_rend), mEnvironment(_env){}
|
||||||
~Actors(){}
|
~Actors();
|
||||||
void setMwRoot(Ogre::SceneNode* root);
|
void setMwRoot(Ogre::SceneNode* root);
|
||||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||||
void insertCreature (const MWWorld::Ptr& ptr);
|
void insertCreature (const MWWorld::Ptr& ptr);
|
||||||
|
|
|
@ -4,7 +4,30 @@
|
||||||
namespace MWRender{
|
namespace MWRender{
|
||||||
std::map<std::string, int> Animation::mUniqueIDs;
|
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){
|
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){
|
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){
|
||||||
shapeNumber = 0;
|
shapeNumber = 0;
|
||||||
|
|
||||||
|
if (allshapes == NULL || creaturemodel == NULL || skel == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
|
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
|
||||||
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)
|
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)
|
||||||
|
|
||||||
|
|
|
@ -60,14 +60,14 @@ class Animation{
|
||||||
std::string getUniqueID(std::string mesh);
|
std::string getUniqueID(std::string mesh);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend): mRend(_rend), mEnvironment(_env), animate(0){};
|
Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
||||||
virtual void runAnimation(float timepassed) = 0;
|
virtual void runAnimation(float timepassed) = 0;
|
||||||
void startScript(std::string groupname, int mode, int loops);
|
void startScript(std::string groupname, int mode, int loops);
|
||||||
void stopScript();
|
void stopScript();
|
||||||
|
|
||||||
|
|
||||||
virtual ~Animation();
|
virtual ~Animation();
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "creatureanimation.hpp"
|
#include "creatureanimation.hpp"
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
|
||||||
#include "../mwworld/world.hpp"
|
#include "../mwworld/world.hpp"
|
||||||
|
|
||||||
|
@ -20,6 +21,28 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environme
|
||||||
std::string meshNumbered = mesh + getUniqueID(mesh) + ">|";
|
std::string meshNumbered = mesh + getUniqueID(mesh) + ">|";
|
||||||
NifOgre::NIFLoader::load(meshNumbered);
|
NifOgre::NIFLoader::load(meshNumbered);
|
||||||
base = mRend.getScene()->createEntity(meshNumbered);
|
base = mRend.getScene()->createEntity(meshNumbered);
|
||||||
|
base->setVisibilityFlags(RV_Actors);
|
||||||
|
|
||||||
|
bool transparent = false;
|
||||||
|
for (unsigned int i=0; i<base->getNumSubEntities(); ++i)
|
||||||
|
{
|
||||||
|
Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial();
|
||||||
|
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
|
||||||
|
while (techIt.hasMoreElements())
|
||||||
|
{
|
||||||
|
Ogre::Technique* tech = techIt.getNext();
|
||||||
|
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
|
||||||
|
while (passIt.hasMoreElements())
|
||||||
|
{
|
||||||
|
Ogre::Pass* pass = passIt.getNext();
|
||||||
|
|
||||||
|
if (pass->getDepthWriteEnabled() == false)
|
||||||
|
transparent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
|
||||||
|
|
||||||
std::string meshZero = mesh + "0000>|";
|
std::string meshZero = mesh + "0000>|";
|
||||||
|
|
||||||
if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){
|
if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){
|
||||||
|
|
|
@ -2,37 +2,283 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "OgreRoot.h"
|
#include <OgreNode.h>
|
||||||
#include "OgreRenderWindow.h"
|
#include <OgreSceneManager.h>
|
||||||
#include "OgreSceneManager.h"
|
#include <OgreMaterial.h>
|
||||||
#include "OgreViewport.h"
|
#include <OgreMaterialManager.h>
|
||||||
#include "OgreCamera.h"
|
|
||||||
#include "OgreTextureManager.h"
|
|
||||||
|
|
||||||
#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone
|
#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone
|
||||||
|
#include "../mwworld/environment.hpp"
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include <components/esm/loadstat.hpp>
|
#include <components/esm/loadstat.hpp>
|
||||||
|
#include <components/esm/loadpgrd.hpp>
|
||||||
|
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
|
|
||||||
using namespace MWRender;
|
|
||||||
using namespace Ogre;
|
using namespace Ogre;
|
||||||
|
|
||||||
Debugging::Debugging(OEngine::Physic::PhysicEngine* engine){
|
namespace MWRender
|
||||||
eng = engine;
|
{
|
||||||
|
|
||||||
|
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){
|
bool Debugging::toggleRenderMode (int mode){
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case MWWorld::World::Render_CollisionDebug:
|
case MWWorld::World::Render_CollisionDebug:
|
||||||
|
|
||||||
// TODO use a proper function instead of accessing the member variable
|
return mEngine->toggleDebugRendering();
|
||||||
// directly.
|
|
||||||
eng->setDebugRenderingMode (!eng->isDebugCreated);
|
case MWWorld::World::Render_Pathgrid:
|
||||||
return eng->isDebugCreated;
|
togglePathgrid();
|
||||||
|
return mPathgridEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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 <utility>
|
||||||
#include <openengine/ogre/renderer.hpp>
|
#include <openengine/ogre/renderer.hpp>
|
||||||
#include <openengine/bullet/physic.hpp>
|
#include <openengine/bullet/physic.hpp>
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -22,20 +23,58 @@ namespace Ogre
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class World;
|
class World;
|
||||||
|
class Environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
class Player;
|
class Player;
|
||||||
|
|
||||||
class Debugging{
|
class Debugging
|
||||||
OEngine::Physic::PhysicEngine* eng;
|
{
|
||||||
|
OEngine::Physic::PhysicEngine* mEngine;
|
||||||
|
Ogre::SceneManager *mSceneMgr;
|
||||||
|
MWWorld::Environment& mEnvironment;
|
||||||
|
|
||||||
|
// Path grid stuff
|
||||||
|
bool mPathgridEnabled;
|
||||||
|
|
||||||
public:
|
void togglePathgrid();
|
||||||
Debugging(OEngine::Physic::PhysicEngine* engine);
|
|
||||||
bool toggleRenderMode (int mode);
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
#include "renderingmanager.hpp"
|
#include "renderingmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/environment.hpp"
|
#include "../mwworld/environment.hpp"
|
||||||
|
#include "../mwworld/world.hpp"
|
||||||
#include "../mwgui/window_manager.hpp"
|
#include "../mwgui/window_manager.hpp"
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
|
||||||
#include <OgreOverlayManager.h>
|
#include <OgreOverlayManager.h>
|
||||||
#include <OgreMaterialManager.h>
|
#include <OgreMaterialManager.h>
|
||||||
|
@ -10,16 +12,24 @@
|
||||||
using namespace MWRender;
|
using namespace MWRender;
|
||||||
using namespace Ogre;
|
using namespace Ogre;
|
||||||
|
|
||||||
LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWWorld::Environment* env)
|
LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering, MWWorld::Environment* env) :
|
||||||
|
mInterior(false), mCellX(0), mCellY(0)
|
||||||
{
|
{
|
||||||
mRendering = rend;
|
mRendering = rend;
|
||||||
|
mRenderingManager = rendering;
|
||||||
mEnvironment = env;
|
mEnvironment = env;
|
||||||
|
|
||||||
|
mCameraPosNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode();
|
||||||
|
mCameraRotNode = mCameraPosNode->createChildSceneNode();
|
||||||
|
mCameraNode = mCameraRotNode->createChildSceneNode();
|
||||||
|
|
||||||
mCellCamera = mRendering->getScene()->createCamera("CellCamera");
|
mCellCamera = mRendering->getScene()->createCamera("CellCamera");
|
||||||
mCellCamera->setProjectionType(PT_ORTHOGRAPHIC);
|
mCellCamera->setProjectionType(PT_ORTHOGRAPHIC);
|
||||||
// look down -y
|
// look down -y
|
||||||
const float sqrt0pt5 = 0.707106781;
|
const float sqrt0pt5 = 0.707106781;
|
||||||
mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0));
|
mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0));
|
||||||
|
|
||||||
|
mCameraNode->attachObject(mCellCamera);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalMap::~LocalMap()
|
LocalMap::~LocalMap()
|
||||||
|
@ -27,13 +37,14 @@ LocalMap::~LocalMap()
|
||||||
deleteBuffers();
|
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()
|
void LocalMap::deleteBuffers()
|
||||||
{
|
{
|
||||||
for (std::map<std::string, uint32*>::iterator it=mBuffers.begin();
|
|
||||||
it != mBuffers.end(); ++it)
|
|
||||||
{
|
|
||||||
delete it->second;
|
|
||||||
}
|
|
||||||
mBuffers.clear();
|
mBuffers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,9 +81,6 @@ void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell)
|
||||||
{
|
{
|
||||||
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
|
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
|
||||||
Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z);
|
Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z);
|
||||||
/// \todo why is this workaround needed?
|
|
||||||
min *= 1.3;
|
|
||||||
max *= 1.3;
|
|
||||||
Vector2 length = max-min;
|
Vector2 length = max-min;
|
||||||
|
|
||||||
// divide into segments
|
// divide into segments
|
||||||
|
@ -95,11 +103,15 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell)
|
||||||
{
|
{
|
||||||
mInterior = false;
|
mInterior = false;
|
||||||
|
|
||||||
|
mCameraRotNode->setOrientation(Quaternion::IDENTITY);
|
||||||
|
|
||||||
std::string name = "Cell_"+coordStr(cell->cell->data.gridX, cell->cell->data.gridY);
|
std::string name = "Cell_"+coordStr(cell->cell->data.gridX, cell->cell->data.gridY);
|
||||||
|
|
||||||
int x = cell->cell->data.gridX;
|
int x = cell->cell->data.gridX;
|
||||||
int y = cell->cell->data.gridY;
|
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);
|
render((x+0.5)*sSize, (-y-0.5)*sSize, -10000, 10000, sSize, sSize, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,17 +120,41 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell,
|
||||||
{
|
{
|
||||||
mInterior = true;
|
mInterior = true;
|
||||||
mBounds = bounds;
|
mBounds = bounds;
|
||||||
|
|
||||||
Vector2 z(bounds.getMaximum().y, bounds.getMinimum().y);
|
|
||||||
Vector2 min(bounds.getMinimum().x, bounds.getMinimum().z);
|
|
||||||
Vector2 max(bounds.getMaximum().x, bounds.getMaximum().z);
|
|
||||||
|
|
||||||
/// \todo why is this workaround needed?
|
Vector2 z(mBounds.getMaximum().y, mBounds.getMinimum().y);
|
||||||
min *= 1.3;
|
|
||||||
max *= 1.3;
|
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;
|
Vector2 length = max-min;
|
||||||
Vector2 center(bounds.getCenter().x, bounds.getCenter().z);
|
|
||||||
|
mCameraPosNode->setPosition(Vector3(center.x, 0, center.y));
|
||||||
|
|
||||||
// divide into segments
|
// divide into segments
|
||||||
const int segsX = std::ceil( length.x / sSize );
|
const int segsX = std::ceil( length.x / sSize );
|
||||||
|
@ -133,7 +169,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell,
|
||||||
Vector2 start = min + Vector2(sSize*x,sSize*y);
|
Vector2 start = min + Vector2(sSize*x,sSize*y);
|
||||||
Vector2 newcenter = start + 4096;
|
Vector2 newcenter = start + 4096;
|
||||||
|
|
||||||
render(newcenter.x, newcenter.y, z.y, z.x, sSize, sSize,
|
render(newcenter.x - center.x, newcenter.y - center.y, z.y, z.x, sSize, sSize,
|
||||||
cell->cell->name + "_" + coordStr(x,y));
|
cell->cell->name + "_" + coordStr(x,y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,8 +188,9 @@ void LocalMap::render(const float x, const float y,
|
||||||
|
|
||||||
// make everything visible
|
// make everything visible
|
||||||
mRendering->getScene()->setAmbientLight(ColourValue(1,1,1));
|
mRendering->getScene()->setAmbientLight(ColourValue(1,1,1));
|
||||||
|
mRenderingManager->disableLights();
|
||||||
|
|
||||||
mCellCamera->setPosition(Vector3(x, zhigh+100000, y));
|
mCameraNode->setPosition(Vector3(x, zhigh+100000, y));
|
||||||
//mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 );
|
//mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 );
|
||||||
mCellCamera->setFarClipDistance(0); // infinite
|
mCellCamera->setFarClipDistance(0); // infinite
|
||||||
|
|
||||||
|
@ -187,7 +224,10 @@ void LocalMap::render(const float x, const float y,
|
||||||
vp->setOverlaysEnabled(false);
|
vp->setOverlaysEnabled(false);
|
||||||
vp->setShadowsEnabled(false);
|
vp->setShadowsEnabled(false);
|
||||||
vp->setBackgroundColour(ColourValue(0, 0, 0));
|
vp->setBackgroundColour(ColourValue(0, 0, 0));
|
||||||
//vp->setVisibilityMask( ... );
|
vp->setVisibilityMask(RV_Map);
|
||||||
|
|
||||||
|
// use fallback techniques without shadows and without mrt
|
||||||
|
vp->setMaterialScheme("Fallback");
|
||||||
|
|
||||||
rtt->update();
|
rtt->update();
|
||||||
|
|
||||||
|
@ -202,16 +242,16 @@ void LocalMap::render(const float x, const float y,
|
||||||
TU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
|
TU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
|
||||||
|
|
||||||
// create a buffer to use for dynamic operations
|
// create a buffer to use for dynamic operations
|
||||||
uint32* buffer = new uint32[sFogOfWarResolution*sFogOfWarResolution];
|
std::vector<uint32> buffer;
|
||||||
|
buffer.resize(sFogOfWarResolution*sFogOfWarResolution);
|
||||||
|
|
||||||
// initialize to (0, 0, 0, 1)
|
// initialize to (0, 0, 0, 1)
|
||||||
uint32* pointer = buffer;
|
|
||||||
for (int p=0; p<sFogOfWarResolution*sFogOfWarResolution; ++p)
|
for (int p=0; p<sFogOfWarResolution*sFogOfWarResolution; ++p)
|
||||||
{
|
{
|
||||||
*(pointer+p) = (255 << 24);
|
buffer[p] = (255 << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(tex2->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), buffer, sFogOfWarResolution*sFogOfWarResolution*4);
|
memcpy(tex2->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4);
|
||||||
tex2->getBuffer()->unlock();
|
tex2->getBuffer()->unlock();
|
||||||
|
|
||||||
mBuffers[texture] = buffer;
|
mBuffers[texture] = buffer;
|
||||||
|
@ -220,13 +260,14 @@ void LocalMap::render(const float x, const float y,
|
||||||
//rtt->writeContentsToFile("./" + texture + ".jpg");
|
//rtt->writeContentsToFile("./" + texture + ".jpg");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mRenderingManager->enableLights();
|
||||||
|
|
||||||
// re-enable fog
|
// re-enable fog
|
||||||
mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd);
|
mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Vector3& direction)
|
void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation)
|
||||||
{
|
{
|
||||||
if (sFogOfWarSkip != 0)
|
if (sFogOfWarSkip != 0)
|
||||||
{
|
{
|
||||||
|
@ -237,7 +278,19 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Vector3&
|
||||||
|
|
||||||
// retrieve the x,y grid coordinates the player is in
|
// retrieve the x,y grid coordinates the player is in
|
||||||
int x,y;
|
int x,y;
|
||||||
Vector2 pos(position.x, position.z);
|
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)
|
if (!mInterior)
|
||||||
{
|
{
|
||||||
x = std::ceil(pos.x / sSize)-1;
|
x = std::ceil(pos.x / sSize)-1;
|
||||||
|
@ -247,9 +300,6 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Vector3&
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
|
|
||||||
min *= 1.3;
|
|
||||||
|
|
||||||
x = std::ceil((pos.x - min.x)/sSize)-1;
|
x = std::ceil((pos.x - min.x)/sSize)-1;
|
||||||
y = std::ceil((pos.y - min.y)/sSize)-1;
|
y = std::ceil((pos.y - min.y)/sSize)-1;
|
||||||
|
|
||||||
|
@ -264,20 +314,17 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Vector3&
|
||||||
u = std::abs((pos.x - (sSize*x))/sSize);
|
u = std::abs((pos.x - (sSize*x))/sSize);
|
||||||
v = 1-std::abs((pos.y + (sSize*y))/sSize);
|
v = 1-std::abs((pos.y + (sSize*y))/sSize);
|
||||||
texName = "Cell_"+coordStr(x,y);
|
texName = "Cell_"+coordStr(x,y);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
|
|
||||||
min *= 1.3;
|
|
||||||
|
|
||||||
u = (pos.x - min.x - sSize*x)/sSize;
|
u = (pos.x - min.x - sSize*x)/sSize;
|
||||||
v = (pos.y - min.y - sSize*y)/sSize;
|
v = (pos.y - min.y - sSize*y)/sSize;
|
||||||
|
|
||||||
texName = mInteriorName + "_" + coordStr(x,y);
|
texName = mInteriorName + "_" + coordStr(x,y);
|
||||||
}
|
}
|
||||||
|
|
||||||
mEnvironment->mWindowManager->setPlayerPos(u, v);
|
mEnvironment->mWindowManager->setPlayerPos(u, v);
|
||||||
mEnvironment->mWindowManager->setPlayerDir(direction.x, -direction.z);
|
mEnvironment->mWindowManager->setPlayerDir(playerdirection.x, -playerdirection.z);
|
||||||
|
|
||||||
// explore radius (squared)
|
// explore radius (squared)
|
||||||
const float sqrExploreRadius = 0.01 * sFogOfWarResolution*sFogOfWarResolution;
|
const float sqrExploreRadius = 0.01 * sFogOfWarResolution*sFogOfWarResolution;
|
||||||
|
@ -288,25 +335,23 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Vector3&
|
||||||
{
|
{
|
||||||
// get its buffer
|
// get its buffer
|
||||||
if (mBuffers.find(texName) == mBuffers.end()) return;
|
if (mBuffers.find(texName) == mBuffers.end()) return;
|
||||||
uint32* buffer = mBuffers[texName];
|
int i=0;
|
||||||
uint32* pointer = buffer;
|
|
||||||
for (int texV = 0; texV<sFogOfWarResolution; ++texV)
|
for (int texV = 0; texV<sFogOfWarResolution; ++texV)
|
||||||
{
|
{
|
||||||
for (int texU = 0; texU<sFogOfWarResolution; ++texU)
|
for (int texU = 0; texU<sFogOfWarResolution; ++texU)
|
||||||
{
|
{
|
||||||
float sqrDist = Math::Sqr(texU - u*sFogOfWarResolution) + Math::Sqr(texV - v*sFogOfWarResolution);
|
float sqrDist = Math::Sqr(texU - u*sFogOfWarResolution) + Math::Sqr(texV - v*sFogOfWarResolution);
|
||||||
uint32 clr = *pointer;
|
uint32 clr = mBuffers[texName][i];
|
||||||
uint8 alpha = (clr >> 24);
|
uint8 alpha = (clr >> 24);
|
||||||
alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) );
|
alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) );
|
||||||
*((uint32*)pointer) = (alpha << 24);
|
mBuffers[texName][i] = (uint32) (alpha << 24);
|
||||||
|
|
||||||
// move to next texel
|
++i;
|
||||||
++pointer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy to the texture
|
// copy to the texture
|
||||||
memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), buffer, sFogOfWarResolution*sFogOfWarResolution*4);
|
memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &mBuffers[texName][0], sFogOfWarResolution*sFogOfWarResolution*4);
|
||||||
tex->getBuffer()->unlock();
|
tex->getBuffer()->unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,15 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
class RenderingManager;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Local map rendering
|
/// \brief Local map rendering
|
||||||
///
|
///
|
||||||
class LocalMap
|
class LocalMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LocalMap(OEngine::Render::OgreRenderer*, MWWorld::Environment* env);
|
LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering, MWWorld::Environment* env);
|
||||||
~LocalMap();
|
~LocalMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,9 +46,9 @@ namespace MWRender
|
||||||
* @remarks This is used to draw a "fog of war" effect
|
* @remarks This is used to draw a "fog of war" effect
|
||||||
* to hide areas on the map the player has not discovered yet.
|
* to hide areas on the map the player has not discovered yet.
|
||||||
* @param position (OGRE coordinates)
|
* @param position (OGRE coordinates)
|
||||||
* @param view direction (OGRE coordinates)
|
* @param camera orientation (OGRE coordinates)
|
||||||
*/
|
*/
|
||||||
void updatePlayer (const Ogre::Vector3& position, const Ogre::Vector3& direction);
|
void updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the fog of war for the current cell to disk.
|
* Save the fog of war for the current cell to disk.
|
||||||
|
@ -58,6 +60,7 @@ namespace MWRender
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OEngine::Render::OgreRenderer* mRendering;
|
OEngine::Render::OgreRenderer* mRendering;
|
||||||
|
MWRender::RenderingManager* mRenderingManager;
|
||||||
MWWorld::Environment* mEnvironment;
|
MWWorld::Environment* mEnvironment;
|
||||||
|
|
||||||
// 1024*1024 pixels for a cell
|
// 1024*1024 pixels for a cell
|
||||||
|
@ -73,6 +76,12 @@ namespace MWRender
|
||||||
static const int sSize = 8192;
|
static const int sSize = 8192;
|
||||||
|
|
||||||
Ogre::Camera* mCellCamera;
|
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,
|
void render(const float x, const float y,
|
||||||
const float zlow, const float zhigh,
|
const float zlow, const float zhigh,
|
||||||
|
@ -86,7 +95,7 @@ namespace MWRender
|
||||||
// a buffer for the "fog of war" texture of the current cell.
|
// a buffer for the "fog of war" texture of the current cell.
|
||||||
// interior cells could be divided into multiple textures,
|
// interior cells could be divided into multiple textures,
|
||||||
// so we store in a map.
|
// so we store in a map.
|
||||||
std::map <std::string, Ogre::uint32*> mBuffers;
|
std::map <std::string, std::vector<Ogre::uint32> > mBuffers;
|
||||||
|
|
||||||
void deleteBuffers();
|
void deleteBuffers();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "npcanimation.hpp"
|
#include "npcanimation.hpp"
|
||||||
#include "../mwworld/world.hpp"
|
#include "../mwworld/world.hpp"
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
|
||||||
|
|
||||||
using namespace Ogre;
|
using namespace Ogre;
|
||||||
|
@ -65,6 +66,27 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
|
||||||
NifOgre::NIFLoader::load(smodel);
|
NifOgre::NIFLoader::load(smodel);
|
||||||
|
|
||||||
base = mRend.getScene()->createEntity(smodel);
|
base = mRend.getScene()->createEntity(smodel);
|
||||||
|
base->setVisibilityFlags(RV_Actors);
|
||||||
|
bool transparent = false;
|
||||||
|
for (unsigned int i=0; i<base->getNumSubEntities(); ++i)
|
||||||
|
{
|
||||||
|
Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial();
|
||||||
|
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
|
||||||
|
while (techIt.hasMoreElements())
|
||||||
|
{
|
||||||
|
Ogre::Technique* tech = techIt.getNext();
|
||||||
|
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
|
||||||
|
while (passIt.hasMoreElements())
|
||||||
|
{
|
||||||
|
Ogre::Pass* pass = passIt.getNext();
|
||||||
|
|
||||||
|
if (pass->getDepthWriteEnabled() == false)
|
||||||
|
transparent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
|
||||||
|
|
||||||
base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones
|
base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones
|
||||||
//stay in the same place when we skipanim, or open a gui window
|
//stay in the same place when we skipanim, or open a gui window
|
||||||
|
|
||||||
|
@ -218,6 +240,7 @@ Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::stri
|
||||||
|
|
||||||
NIFLoader::load(mesh);
|
NIFLoader::load(mesh);
|
||||||
Entity* ent = mRend.getScene()->createEntity(mesh);
|
Entity* ent = mRend.getScene()->createEntity(mesh);
|
||||||
|
ent->setVisibilityFlags(RV_Actors);
|
||||||
|
|
||||||
base->attachObjectToBone(bonename, ent);
|
base->attachObjectToBone(bonename, ent);
|
||||||
return ent;
|
return ent;
|
||||||
|
@ -227,9 +250,7 @@ void NpcAnimation::insertFreePart(const std::string &mesh, const std::string suf
|
||||||
NIFLoader::load(meshNumbered);
|
NIFLoader::load(meshNumbered);
|
||||||
|
|
||||||
Ogre::Entity* ent = mRend.getScene()->createEntity(meshNumbered);
|
Ogre::Entity* ent = mRend.getScene()->createEntity(meshNumbered);
|
||||||
|
ent->setVisibilityFlags(RV_Actors);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
insert->attachObject(ent);
|
insert->attachObject(ent);
|
||||||
entityparts.push_back(ent);
|
entityparts.push_back(ent);
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
|
|
||||||
#include <components/nifogre/ogre_nif_loader.hpp>
|
#include <components/nifogre/ogre_nif_loader.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
|
||||||
using namespace MWRender;
|
using namespace MWRender;
|
||||||
|
|
||||||
|
@ -88,38 +90,112 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||||
NifOgre::NIFLoader::load(mesh);
|
NifOgre::NIFLoader::load(mesh);
|
||||||
Ogre::Entity *ent = mRenderer.getScene()->createEntity(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);
|
||||||
|
|
||||||
|
bool transparent = false;
|
||||||
|
for (unsigned int i=0; i<ent->getNumSubEntities(); ++i)
|
||||||
|
{
|
||||||
|
Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial();
|
||||||
|
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
|
||||||
|
while (techIt.hasMoreElements())
|
||||||
|
{
|
||||||
|
Ogre::Technique* tech = techIt.getNext();
|
||||||
|
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
|
||||||
|
while (passIt.hasMoreElements())
|
||||||
|
{
|
||||||
|
Ogre::Pass* pass = passIt.getNext();
|
||||||
|
|
||||||
|
if (pass->getDepthWriteEnabled() == false)
|
||||||
|
transparent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects"))
|
||||||
{
|
{
|
||||||
insert->attachObject(ent);
|
insert->attachObject(ent);
|
||||||
|
|
||||||
|
ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0);
|
||||||
|
ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc);
|
||||||
|
ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Ogre::StaticGeometry* sg = 0;
|
Ogre::StaticGeometry* sg = 0;
|
||||||
if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
|
||||||
|
/* if (transparent)
|
||||||
{
|
{
|
||||||
uniqueID = uniqueID +1;
|
if( mStaticGeometryAlpha.find(ptr.getCell()) == mStaticGeometryAlpha.end())
|
||||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
{
|
||||||
//Create the scenenode and put it in the map
|
uniqueID = uniqueID +1;
|
||||||
mStaticGeometry[ptr.getCell()] = sg;
|
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||||
|
mStaticGeometryAlpha[ptr.getCell()] = sg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sg = mStaticGeometryAlpha[ptr.getCell()];
|
||||||
|
}
|
||||||
|
else*/ if (small)
|
||||||
|
{
|
||||||
|
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
||||||
|
{
|
||||||
|
uniqueID = uniqueID +1;
|
||||||
|
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||||
|
mStaticGeometrySmall[ptr.getCell()] = sg;
|
||||||
|
|
||||||
// This specifies the size of a single batch region.
|
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
||||||
// If it is set too high:
|
}
|
||||||
// - there will be problems choosing the correct lights
|
else
|
||||||
// - the culling will be more inefficient
|
sg = mStaticGeometrySmall[ptr.getCell()];
|
||||||
// If it is set too low:
|
|
||||||
// - there will be too many batches.
|
|
||||||
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
|
|
||||||
|
|
||||||
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
|
|
||||||
mBounds[ptr.getCell()].merge(ent->getBoundingBox());
|
|
||||||
}
|
}
|
||||||
else
|
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());
|
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
|
||||||
mBounds[ptr.getCell()].merge(insert->_getDerivedPosition());
|
|
||||||
|
sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics);
|
||||||
|
|
||||||
|
sg->setCastShadows(true);
|
||||||
|
|
||||||
|
sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
|
||||||
|
|
||||||
mRenderer.getScene()->destroyEntity(ent);
|
mRenderer.getScene()->destroyEntity(ent);
|
||||||
}
|
}
|
||||||
|
@ -131,6 +207,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f
|
||||||
assert(insert);
|
assert(insert);
|
||||||
Ogre::Light *light = mRenderer.getScene()->createLight();
|
Ogre::Light *light = mRenderer.getScene()->createLight();
|
||||||
light->setDiffuseColour (r, g, b);
|
light->setDiffuseColour (r, g, b);
|
||||||
|
mLights.push_back(light->getName());
|
||||||
|
|
||||||
float cval=0.0f, lval=0.0f, qval=0.0f;
|
float cval=0.0f, lval=0.0f, qval=0.0f;
|
||||||
|
|
||||||
|
@ -206,7 +283,21 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
||||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||||
sg = 0;
|
sg = 0;
|
||||||
}
|
}
|
||||||
|
if(mStaticGeometrySmall.find(store) != mStaticGeometrySmall.end())
|
||||||
|
{
|
||||||
|
Ogre::StaticGeometry* sg = mStaticGeometrySmall[store];
|
||||||
|
mStaticGeometrySmall.erase(store);
|
||||||
|
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||||
|
sg = 0;
|
||||||
|
}
|
||||||
|
/*if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end())
|
||||||
|
{
|
||||||
|
Ogre::StaticGeometry* sg = mStaticGeometryAlpha[store];
|
||||||
|
mStaticGeometryAlpha.erase(store);
|
||||||
|
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||||
|
sg = 0;
|
||||||
|
}*/
|
||||||
|
|
||||||
if(mBounds.find(store) != mBounds.end())
|
if(mBounds.find(store) != mBounds.end())
|
||||||
mBounds.erase(store);
|
mBounds.erase(store);
|
||||||
}
|
}
|
||||||
|
@ -218,9 +309,50 @@ void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
|
||||||
Ogre::StaticGeometry* sg = mStaticGeometry[&cell];
|
Ogre::StaticGeometry* sg = mStaticGeometry[&cell];
|
||||||
sg->build();
|
sg->build();
|
||||||
}
|
}
|
||||||
|
if(mStaticGeometrySmall.find(&cell) != mStaticGeometrySmall.end())
|
||||||
|
{
|
||||||
|
Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell];
|
||||||
|
sg->build();
|
||||||
|
}
|
||||||
|
/*if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end())
|
||||||
|
{
|
||||||
|
Ogre::StaticGeometry* sg = mStaticGeometryAlpha[&cell];
|
||||||
|
sg->build();
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
||||||
{
|
{
|
||||||
return mBounds[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,7 +14,10 @@ class Objects{
|
||||||
OEngine::Render::OgreRenderer &mRenderer;
|
OEngine::Render::OgreRenderer &mRenderer;
|
||||||
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
||||||
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
|
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
|
||||||
|
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
|
||||||
|
//std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometryAlpha;
|
||||||
std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds;
|
std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds;
|
||||||
|
std::vector<std::string> mLights;
|
||||||
Ogre::SceneNode* mMwRoot;
|
Ogre::SceneNode* mMwRoot;
|
||||||
bool mIsStatic;
|
bool mIsStatic;
|
||||||
static int uniqueID;
|
static int uniqueID;
|
||||||
|
@ -43,6 +46,9 @@ public:
|
||||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
|
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 insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius);
|
||||||
|
|
||||||
|
void enableLights();
|
||||||
|
void disableLights();
|
||||||
|
|
||||||
Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*);
|
Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*);
|
||||||
///< get a bounding box that encloses all objects in the specified cell
|
///< get a bounding box that encloses all objects in the specified cell
|
||||||
|
|
||||||
|
|
304
apps/openmw/mwrender/occlusionquery.cpp
Normal file
304
apps/openmw/mwrender/occlusionquery.cpp
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
#include "occlusionquery.hpp"
|
||||||
|
#include "renderconst.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->setCastShadows(false);
|
||||||
|
mBBQueryTotal->setDefaultDimensions(150, 150);
|
||||||
|
mBBQueryTotal->createBillboard(Vector3::ZERO);
|
||||||
|
mBBQueryTotal->setMaterialName("QueryTotalPixels");
|
||||||
|
mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1);
|
||||||
|
mBBNodeReal->attachObject(mBBQueryTotal);
|
||||||
|
|
||||||
|
mBBQueryVisible = mRendering->getScene()->createBillboardSet(1);
|
||||||
|
mBBQueryVisible->setCastShadows(false);
|
||||||
|
mBBQueryVisible->setDefaultDimensions(150, 150);
|
||||||
|
mBBQueryVisible->createBillboard(Vector3::ZERO);
|
||||||
|
mBBQueryVisible->setMaterialName("QueryVisiblePixels");
|
||||||
|
mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1);
|
||||||
|
mBBNodeReal->attachObject(mBBQueryVisible);
|
||||||
|
|
||||||
|
mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1);
|
||||||
|
/// \todo ideally this should occupy exactly 1 pixel on the screen
|
||||||
|
mBBQuerySingleObject->setCastShadows(false);
|
||||||
|
mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003);
|
||||||
|
mBBQuerySingleObject->createBillboard(Vector3::ZERO);
|
||||||
|
mBBQuerySingleObject->setMaterialName("QueryVisiblePixels");
|
||||||
|
mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery);
|
||||||
|
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 == RQG_SkiesLate)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
105
apps/openmw/mwrender/occlusionquery.hpp
Normal file
105
apps/openmw/mwrender/occlusionquery.hpp
Normal file
|
@ -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
|
62
apps/openmw/mwrender/renderconst.hpp
Normal file
62
apps/openmw/mwrender/renderconst.hpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef GAME_RENDER_CONST_H
|
||||||
|
#define GAME_RENDER_CONST_H
|
||||||
|
|
||||||
|
#include <OgreRenderQueue.h>
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
|
||||||
|
// Render queue groups
|
||||||
|
enum RenderQueueGroups
|
||||||
|
{
|
||||||
|
// Sky early (atmosphere, clouds, moons)
|
||||||
|
RQG_SkiesEarly = Ogre::RENDER_QUEUE_SKIES_EARLY,
|
||||||
|
|
||||||
|
RQG_Main = Ogre::RENDER_QUEUE_MAIN,
|
||||||
|
|
||||||
|
RQG_Water = Ogre::RENDER_QUEUE_7+1,
|
||||||
|
|
||||||
|
RQG_Alpha = Ogre::RENDER_QUEUE_MAIN,
|
||||||
|
|
||||||
|
RQG_UnderWater = Ogre::RENDER_QUEUE_7+1,
|
||||||
|
|
||||||
|
RQG_OcclusionQuery = Ogre::RENDER_QUEUE_8,
|
||||||
|
|
||||||
|
// Sky late (sun & sun flare)
|
||||||
|
RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE
|
||||||
|
};
|
||||||
|
|
||||||
|
// Visibility flags
|
||||||
|
enum VisibilityFlags
|
||||||
|
{
|
||||||
|
// Terrain
|
||||||
|
RV_Terrain = 1,
|
||||||
|
|
||||||
|
// Statics (e.g. trees, houses)
|
||||||
|
RV_Statics = 2,
|
||||||
|
|
||||||
|
// Small statics
|
||||||
|
RV_StaticsSmall = 4,
|
||||||
|
|
||||||
|
// Water
|
||||||
|
RV_Water = 8,
|
||||||
|
|
||||||
|
// Actors (player, npcs, creatures)
|
||||||
|
RV_Actors = 16,
|
||||||
|
|
||||||
|
// Misc objects (containers, dynamic objects)
|
||||||
|
RV_Misc = 32,
|
||||||
|
|
||||||
|
RV_Sky = 64,
|
||||||
|
|
||||||
|
// Sun glare (not visible in reflection)
|
||||||
|
RV_Glare = 128,
|
||||||
|
|
||||||
|
RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water,
|
||||||
|
|
||||||
|
/// \todo markers (normally hidden)
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -12,7 +12,12 @@
|
||||||
#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone
|
#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include <components/esm/loadstat.hpp>
|
#include <components/esm/loadstat.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include "shadows.hpp"
|
||||||
|
#include "shaderhelper.hpp"
|
||||||
|
#include "localmap.hpp"
|
||||||
|
#include "water.hpp"
|
||||||
|
|
||||||
using namespace MWRender;
|
using namespace MWRender;
|
||||||
using namespace Ogre;
|
using namespace Ogre;
|
||||||
|
@ -20,16 +25,54 @@ using namespace Ogre;
|
||||||
namespace MWRender {
|
namespace MWRender {
|
||||||
|
|
||||||
RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment)
|
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), mSunEnabled(0)
|
||||||
{
|
{
|
||||||
mRendering.createScene("PlayerCam", 55, 5);
|
mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5);
|
||||||
|
|
||||||
|
mWater = 0;
|
||||||
|
|
||||||
|
//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)
|
// 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;
|
||||||
|
else if (filter == "none") tfo = TFO_NONE;
|
||||||
|
|
||||||
|
MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
|
||||||
|
MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 );
|
||||||
|
|
||||||
// Load resources
|
// Load resources
|
||||||
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
||||||
|
|
||||||
|
// disable unsupported effects
|
||||||
|
const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
|
||||||
|
if (caps->getNumMultiRenderTargets() < 2)
|
||||||
|
Settings::Manager::setBool("shader", "Water", false);
|
||||||
|
if (!caps->isShaderProfileSupported("fp40") && !caps->isShaderProfileSupported("ps_4_0"))
|
||||||
|
Settings::Manager::setBool("enabled", "Shadows", false);
|
||||||
|
|
||||||
|
// note that the order is important here
|
||||||
|
if (useMRT())
|
||||||
|
{
|
||||||
|
CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbuffer");
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true);
|
||||||
|
CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "Underwater");
|
||||||
|
CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbufferFinalizer");
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "UnderwaterNoMRT");
|
||||||
|
}
|
||||||
|
|
||||||
// Turn the entire scene (represented by the 'root' node) -90
|
// Turn the entire scene (represented by the 'root' node) -90
|
||||||
// degrees around the x axis. This makes Z go upwards, and Y go into
|
// degrees around the x axis. This makes Z go upwards, and Y go into
|
||||||
// the screen (when x is to the right.) This is the orientation that
|
// the screen (when x is to the right.) This is the orientation that
|
||||||
|
@ -40,31 +83,39 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
||||||
mMwRoot->pitch(Degree(-90));
|
mMwRoot->pitch(Degree(-90));
|
||||||
mObjects.setMwRoot(mMwRoot);
|
mObjects.setMwRoot(mMwRoot);
|
||||||
mActors.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");
|
Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player");
|
||||||
playerNode->pitch(Degree(90));
|
playerNode->pitch(Degree(90));
|
||||||
Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode();
|
Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode();
|
||||||
Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode();
|
Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode();
|
||||||
cameraPitchNode->attachObject(mRendering.getCamera());
|
cameraPitchNode->attachObject(mRendering.getCamera());
|
||||||
|
|
||||||
|
mShadows = new Shadows(&mRendering);
|
||||||
|
mShaderHelper = new ShaderHelper(this);
|
||||||
|
|
||||||
|
mTerrainManager = new TerrainManager(mRendering.getScene(), this,
|
||||||
|
environment);
|
||||||
|
|
||||||
//mSkyManager = 0;
|
//mSkyManager = 0;
|
||||||
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment);
|
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment);
|
||||||
|
|
||||||
|
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
|
||||||
|
|
||||||
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
||||||
mSun = 0;
|
mSun = 0;
|
||||||
|
|
||||||
mLocalMap = new MWRender::LocalMap(&mRendering, &environment);
|
mDebugging = new Debugging(mMwRoot, environment, engine);
|
||||||
|
mLocalMap = new MWRender::LocalMap(&mRendering, this, &environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderingManager::~RenderingManager ()
|
RenderingManager::~RenderingManager ()
|
||||||
{
|
{
|
||||||
//TODO: destroy mSun?
|
|
||||||
delete mPlayer;
|
delete mPlayer;
|
||||||
delete mSkyManager;
|
delete mSkyManager;
|
||||||
|
delete mDebugging;
|
||||||
|
delete mTerrainManager;
|
||||||
delete mLocalMap;
|
delete mLocalMap;
|
||||||
|
delete mOcclusionQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWRender::SkyManager* RenderingManager::getSkyManager()
|
MWRender::SkyManager* RenderingManager::getSkyManager()
|
||||||
|
@ -88,14 +139,35 @@ OEngine::Render::Fader* RenderingManager::getFader()
|
||||||
return mRendering.getFader();
|
return mRendering.getFader();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store){
|
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store)
|
||||||
|
{
|
||||||
mObjects.removeCell(store);
|
mObjects.removeCell(store);
|
||||||
mActors.removeCell(store);
|
mActors.removeCell(store);
|
||||||
|
mDebugging->cellRemoved(store);
|
||||||
|
if (store->cell->isExterior())
|
||||||
|
mTerrainManager->cellRemoved(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingManager::removeWater ()
|
||||||
|
{
|
||||||
|
if(mWater){
|
||||||
|
mWater->setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingManager::toggleWater()
|
||||||
|
{
|
||||||
|
if (mWater)
|
||||||
|
mWater->toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
|
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
|
||||||
{
|
{
|
||||||
mObjects.buildStaticGeometry (*store);
|
mObjects.buildStaticGeometry (*store);
|
||||||
|
mDebugging->cellAdded(store);
|
||||||
|
if (store->cell->isExterior())
|
||||||
|
mTerrainManager->cellAdded(store);
|
||||||
|
waterAdded(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::addObject (const MWWorld::Ptr& ptr){
|
void RenderingManager::addObject (const MWWorld::Ptr& ptr){
|
||||||
|
@ -136,18 +208,44 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve
|
||||||
void RenderingManager::update (float duration){
|
void RenderingManager::update (float duration){
|
||||||
|
|
||||||
mActors.update (duration);
|
mActors.update (duration);
|
||||||
|
|
||||||
|
mOcclusionQuery->update(duration);
|
||||||
|
|
||||||
mSkyManager->update(duration);
|
mSkyManager->update(duration);
|
||||||
|
|
||||||
|
mSkyManager->setGlare(mOcclusionQuery->getSunVisibility());
|
||||||
|
|
||||||
mRendering.update(duration);
|
mRendering.update(duration);
|
||||||
|
|
||||||
mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealDirection() );
|
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(), mSkyManager, store->cell);
|
||||||
|
else
|
||||||
|
mWater->changeCell(store->cell);
|
||||||
|
mWater->setActive(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
removeWater();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingManager::setWaterHeight(const float height)
|
||||||
|
{
|
||||||
|
if (mWater)
|
||||||
|
mWater->setHeight(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::skyEnable ()
|
void RenderingManager::skyEnable ()
|
||||||
{
|
{
|
||||||
if(mSkyManager)
|
if(mSkyManager)
|
||||||
mSkyManager->enable();
|
mSkyManager->enable();
|
||||||
|
|
||||||
|
mOcclusionQuery->setSunNode(mSkyManager->getSunNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::skyDisable ()
|
void RenderingManager::skyDisable ()
|
||||||
|
@ -171,7 +269,7 @@ void RenderingManager::skySetDate (int day, int month)
|
||||||
|
|
||||||
int RenderingManager::skyGetMasserPhase() const
|
int RenderingManager::skyGetMasserPhase() const
|
||||||
{
|
{
|
||||||
|
|
||||||
return mSkyManager->getMasserPhase();
|
return mSkyManager->getMasserPhase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,17 +285,31 @@ void RenderingManager::skySetMoonColour (bool red){
|
||||||
|
|
||||||
bool RenderingManager::toggleRenderMode(int mode)
|
bool RenderingManager::toggleRenderMode(int mode)
|
||||||
{
|
{
|
||||||
if (mode == MWWorld::World::Render_CollisionDebug)
|
if (mode != MWWorld::World::Render_Wireframe)
|
||||||
return mDebugging.toggleRenderMode(mode);
|
return mDebugging->toggleRenderMode(mode);
|
||||||
else // if (mode == MWWorld::World::Render_Wireframe)
|
else // if (mode == MWWorld::World::Render_Wireframe)
|
||||||
{
|
{
|
||||||
if (mRendering.getCamera()->getPolygonMode() == PM_SOLID)
|
if (mRendering.getCamera()->getPolygonMode() == PM_SOLID)
|
||||||
{
|
{
|
||||||
|
// disable compositors
|
||||||
|
if (useMRT())
|
||||||
|
{
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", false);
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", false);
|
||||||
|
}
|
||||||
|
|
||||||
mRendering.getCamera()->setPolygonMode(PM_WIREFRAME);
|
mRendering.getCamera()->setPolygonMode(PM_WIREFRAME);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// re-enable compositors
|
||||||
|
if (useMRT())
|
||||||
|
{
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true);
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true);
|
||||||
|
}
|
||||||
|
|
||||||
mRendering.getCamera()->setPolygonMode(PM_SOLID);
|
mRendering.getCamera()->setPolygonMode(PM_SOLID);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -206,27 +318,29 @@ bool RenderingManager::toggleRenderMode(int mode)
|
||||||
|
|
||||||
void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
|
void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
|
||||||
{
|
{
|
||||||
Ogre::ColourValue color;
|
Ogre::ColourValue color;
|
||||||
color.setAsABGR (mCell.cell->ambi.fog);
|
color.setAsABGR (mCell.cell->ambi.fog);
|
||||||
|
|
||||||
configureFog(mCell.cell->ambi.fogDensity, color);
|
configureFog(mCell.cell->ambi.fogDensity, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
|
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
|
||||||
{
|
{
|
||||||
/// \todo make the viewing distance and fog start/end configurable
|
float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance");
|
||||||
|
|
||||||
// right now we load 3x3 cells, so the maximum viewing distance we
|
float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance");
|
||||||
// can allow (to prevent objects suddenly popping up) equals:
|
float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance");
|
||||||
// 8192 * 0.69
|
|
||||||
// ^ cell size ^ minimum density value used (clear weather)
|
|
||||||
float low = 5652.48 / density / 2.f;
|
|
||||||
float high = 5652.48 / density;
|
|
||||||
|
|
||||||
mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high);
|
mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high);
|
||||||
|
|
||||||
mRendering.getCamera()->setFarClipDistance ( high );
|
mRendering.getCamera()->setFarClipDistance ( max / density );
|
||||||
mRendering.getViewport()->setBackgroundColour (colour);
|
mRendering.getViewport()->setBackgroundColour (colour);
|
||||||
|
|
||||||
|
CompositorInstance* inst = CompositorManager::getSingleton().getCompositorChain(mRendering.getViewport())->getCompositor("gbuffer");
|
||||||
|
if (inst != 0)
|
||||||
|
inst->getCompositor()->getTechnique(0)->getTargetPass(0)->getPass(0)->setClearColour(colour);
|
||||||
|
if (mWater)
|
||||||
|
mWater->setViewportBackground(colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,55 +350,62 @@ void RenderingManager::setAmbientMode()
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
|
||||||
mRendering.getScene()->setAmbientLight(mAmbientColor);
|
setAmbientColour(mAmbientColor);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
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;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
|
||||||
mRendering.getScene()->setAmbientLight(ColourValue(1,1,1));
|
setAmbientColour(ColourValue(1,1,1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::configureAmbient(ESMS::CellStore<MWWorld::RefData> &mCell)
|
void RenderingManager::configureAmbient(ESMS::CellStore<MWWorld::RefData> &mCell)
|
||||||
{
|
{
|
||||||
mAmbientColor.setAsABGR (mCell.cell->ambi.ambient);
|
mAmbientColor.setAsABGR (mCell.cell->ambi.ambient);
|
||||||
setAmbientMode();
|
setAmbientMode();
|
||||||
|
|
||||||
// Create a "sun" that shines light downwards. It doesn't look
|
// Create a "sun" that shines light downwards. It doesn't look
|
||||||
// completely right, but leave it for now.
|
// completely right, but leave it for now.
|
||||||
if(!mSun)
|
if(!mSun)
|
||||||
{
|
{
|
||||||
mSun = mRendering.getScene()->createLight();
|
mSun = mRendering.getScene()->createLight();
|
||||||
}
|
}
|
||||||
Ogre::ColourValue colour;
|
Ogre::ColourValue colour;
|
||||||
colour.setAsABGR (mCell.cell->ambi.sunlight);
|
colour.setAsABGR (mCell.cell->ambi.sunlight);
|
||||||
mSun->setDiffuseColour (colour);
|
mSun->setDiffuseColour (colour);
|
||||||
mSun->setType(Ogre::Light::LT_DIRECTIONAL);
|
mSun->setType(Ogre::Light::LT_DIRECTIONAL);
|
||||||
mSun->setDirection(0,-1,0);
|
mSun->setDirection(0,-1,0);
|
||||||
}
|
}
|
||||||
// Switch through lighting modes.
|
// Switch through lighting modes.
|
||||||
|
|
||||||
void RenderingManager::toggleLight()
|
void RenderingManager::toggleLight()
|
||||||
{
|
{
|
||||||
if (mAmbientMode==2)
|
if (mAmbientMode==2)
|
||||||
mAmbientMode = 0;
|
mAmbientMode = 0;
|
||||||
else
|
else
|
||||||
++mAmbientMode;
|
++mAmbientMode;
|
||||||
|
|
||||||
switch (mAmbientMode)
|
switch (mAmbientMode)
|
||||||
{
|
{
|
||||||
case 0: std::cout << "Setting lights to normal\n"; break;
|
case 0: std::cout << "Setting lights to normal\n"; break;
|
||||||
case 1: std::cout << "Turning the lights up\n"; break;
|
case 1: std::cout << "Turning the lights up\n"; break;
|
||||||
case 2: std::cout << "Turning the lights to full\n"; break;
|
case 2: std::cout << "Turning the lights to full\n"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAmbientMode();
|
setAmbientMode();
|
||||||
|
}
|
||||||
|
void RenderingManager::checkUnderwater()
|
||||||
|
{
|
||||||
|
if(mWater)
|
||||||
|
{
|
||||||
|
mWater->checkUnderwater( mRendering.getCamera()->getRealPosition().y );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
|
void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
|
||||||
|
@ -300,30 +421,43 @@ void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr)
|
||||||
|
|
||||||
void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
|
void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
|
||||||
{
|
{
|
||||||
|
if (!mSunEnabled) return;
|
||||||
mSun->setDiffuseColour(colour);
|
mSun->setDiffuseColour(colour);
|
||||||
|
mSun->setSpecularColour(colour);
|
||||||
|
mTerrainManager->setDiffuse(colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
|
void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
|
||||||
{
|
{
|
||||||
mRendering.getScene()->setAmbientLight(colour);
|
mRendering.getScene()->setAmbientLight(colour);
|
||||||
|
mTerrainManager->setAmbient(colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::sunEnable()
|
void RenderingManager::sunEnable()
|
||||||
{
|
{
|
||||||
if (mSun) mSun->setVisible(true);
|
// Don't disable the light, as the shaders assume the first light to be directional.
|
||||||
|
//if (mSun) mSun->setVisible(true);
|
||||||
|
mSunEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::sunDisable()
|
void RenderingManager::sunDisable()
|
||||||
{
|
{
|
||||||
if (mSun) mSun->setVisible(false);
|
// Don't disable the light, as the shaders assume the first light to be directional.
|
||||||
|
//if (mSun) mSun->setVisible(false);
|
||||||
|
mSunEnabled = false;
|
||||||
|
if (mSun)
|
||||||
|
{
|
||||||
|
mSun->setDiffuseColour(ColourValue(0,0,0));
|
||||||
|
mSun->setSpecularColour(ColourValue(0,0,0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
|
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)
|
// 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));
|
if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y));
|
||||||
|
|
||||||
mSkyManager->setSunDirection(direction);
|
mSkyManager->setSunDirection(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,4 +479,26 @@ void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell)
|
||||||
mLocalMap->saveFogOfWar(cell);
|
mLocalMap->saveFogOfWar(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderingManager::disableLights()
|
||||||
|
{
|
||||||
|
mObjects.disableLights();
|
||||||
|
sunDisable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingManager::enableLights()
|
||||||
|
{
|
||||||
|
mObjects.enableLights();
|
||||||
|
sunEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool RenderingManager::useMRT()
|
||||||
|
{
|
||||||
|
return Settings::Manager::getBool("shader", "Water");
|
||||||
|
}
|
||||||
|
|
||||||
|
Shadows* RenderingManager::getShadows()
|
||||||
|
{
|
||||||
|
return mShadows;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "sky.hpp"
|
#include "sky.hpp"
|
||||||
|
#include "terrain.hpp"
|
||||||
#include "debugging.hpp"
|
#include "debugging.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
@ -24,15 +25,12 @@
|
||||||
#include "objects.hpp"
|
#include "objects.hpp"
|
||||||
#include "actors.hpp"
|
#include "actors.hpp"
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "localmap.hpp"
|
#include "occlusionquery.hpp"
|
||||||
|
|
||||||
namespace Ogre
|
namespace Ogre
|
||||||
{
|
{
|
||||||
class Camera;
|
|
||||||
class Viewport;
|
|
||||||
class SceneManager;
|
class SceneManager;
|
||||||
class SceneNode;
|
class SceneNode;
|
||||||
class RaySceneQuery;
|
|
||||||
class Quaternion;
|
class Quaternion;
|
||||||
class Vector3;
|
class Vector3;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +43,10 @@ namespace MWWorld
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Shadows;
|
||||||
|
class ShaderHelper;
|
||||||
|
class LocalMap;
|
||||||
|
class Water;
|
||||||
|
|
||||||
class RenderingManager: private RenderingInterface {
|
class RenderingManager: private RenderingInterface {
|
||||||
|
|
||||||
|
@ -59,6 +60,8 @@ class RenderingManager: private RenderingInterface {
|
||||||
RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment);
|
RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment);
|
||||||
virtual ~RenderingManager();
|
virtual ~RenderingManager();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual MWRender::Player& getPlayer(); /// \todo move this to private again as soon as
|
virtual MWRender::Player& getPlayer(); /// \todo move this to private again as soon as
|
||||||
/// MWWorld::Player has been rewritten to not need access
|
/// MWWorld::Player has been rewritten to not need access
|
||||||
/// to internal details of the rendering system anymore
|
/// to internal details of the rendering system anymore
|
||||||
|
@ -67,7 +70,7 @@ class RenderingManager: private RenderingInterface {
|
||||||
|
|
||||||
void toggleLight();
|
void toggleLight();
|
||||||
bool toggleRenderMode(int mode);
|
bool toggleRenderMode(int mode);
|
||||||
|
|
||||||
OEngine::Render::Fader* getFader();
|
OEngine::Render::Fader* getFader();
|
||||||
|
|
||||||
void removeCell (MWWorld::Ptr::CellStore *store);
|
void removeCell (MWWorld::Ptr::CellStore *store);
|
||||||
|
@ -75,6 +78,11 @@ class RenderingManager: private RenderingInterface {
|
||||||
/// \todo this function should be removed later. Instead the rendering subsystems should track
|
/// \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.
|
/// when rebatching is needed and update automatically at the end of each frame.
|
||||||
void cellAdded (MWWorld::Ptr::CellStore *store);
|
void cellAdded (MWWorld::Ptr::CellStore *store);
|
||||||
|
void waterAdded(MWWorld::Ptr::CellStore *store);
|
||||||
|
|
||||||
|
void removeWater();
|
||||||
|
|
||||||
|
static const bool useMRT();
|
||||||
|
|
||||||
void preCellChange (MWWorld::Ptr::CellStore* store);
|
void preCellChange (MWWorld::Ptr::CellStore* store);
|
||||||
///< this event is fired immediately before changing cell
|
///< this event is fired immediately before changing cell
|
||||||
|
@ -86,17 +94,29 @@ class RenderingManager: private RenderingInterface {
|
||||||
void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale);
|
void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale);
|
||||||
void rotateObject (const MWWorld::Ptr& ptr, const::Ogre::Quaternion& orientation);
|
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).
|
/// \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 moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::Ptr::CellStore *store);
|
||||||
|
|
||||||
void update (float duration);
|
void update (float duration);
|
||||||
|
|
||||||
void setAmbientColour(const Ogre::ColourValue& colour);
|
void setAmbientColour(const Ogre::ColourValue& colour);
|
||||||
void setSunColour(const Ogre::ColourValue& colour);
|
void setSunColour(const Ogre::ColourValue& colour);
|
||||||
void setSunDirection(const Ogre::Vector3& direction);
|
void setSunDirection(const Ogre::Vector3& direction);
|
||||||
void sunEnable();
|
void sunEnable();
|
||||||
void sunDisable();
|
void sunDisable();
|
||||||
|
|
||||||
|
void disableLights();
|
||||||
|
void enableLights();
|
||||||
|
|
||||||
|
bool occlusionQuerySupported() { return mOcclusionQuery->supported(); };
|
||||||
|
OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; };
|
||||||
|
|
||||||
|
Shadows* getShadows();
|
||||||
|
|
||||||
void setGlare(bool glare);
|
void setGlare(bool glare);
|
||||||
void skyEnable ();
|
void skyEnable ();
|
||||||
void skyDisable ();
|
void skyDisable ();
|
||||||
|
@ -109,13 +129,13 @@ class RenderingManager: private RenderingInterface {
|
||||||
|
|
||||||
void requestMap (MWWorld::Ptr::CellStore* cell);
|
void requestMap (MWWorld::Ptr::CellStore* cell);
|
||||||
///< request the local map for a cell
|
///< request the local map for a cell
|
||||||
|
|
||||||
/// configure fog according to cell
|
/// configure fog according to cell
|
||||||
void configureFog(ESMS::CellStore<MWWorld::RefData> &mCell);
|
void configureFog(ESMS::CellStore<MWWorld::RefData> &mCell);
|
||||||
|
|
||||||
/// configure fog manually
|
/// configure fog manually
|
||||||
void configureFog(const float density, const Ogre::ColourValue& colour);
|
void configureFog(const float density, const Ogre::ColourValue& colour);
|
||||||
|
|
||||||
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
|
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
|
||||||
int number = 1);
|
int number = 1);
|
||||||
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
||||||
|
@ -131,9 +151,17 @@ class RenderingManager: private RenderingInterface {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void setAmbientMode();
|
void setAmbientMode();
|
||||||
|
|
||||||
|
bool mSunEnabled;
|
||||||
|
|
||||||
SkyManager* mSkyManager;
|
SkyManager* mSkyManager;
|
||||||
|
|
||||||
|
OcclusionQuery* mOcclusionQuery;
|
||||||
|
|
||||||
|
TerrainManager* mTerrainManager;
|
||||||
|
|
||||||
|
MWRender::Water *mWater;
|
||||||
|
|
||||||
OEngine::Render::OgreRenderer &mRendering;
|
OEngine::Render::OgreRenderer &mRendering;
|
||||||
|
|
||||||
MWRender::Objects mObjects;
|
MWRender::Objects mObjects;
|
||||||
|
@ -149,14 +177,18 @@ class RenderingManager: private RenderingInterface {
|
||||||
/// that the OGRE coordinate system matches that used internally in
|
/// that the OGRE coordinate system matches that used internally in
|
||||||
/// Morrowind.
|
/// Morrowind.
|
||||||
Ogre::SceneNode *mMwRoot;
|
Ogre::SceneNode *mMwRoot;
|
||||||
Ogre::RaySceneQuery *mRaySceneQuery;
|
|
||||||
|
|
||||||
OEngine::Physic::PhysicEngine* mPhysicsEngine;
|
OEngine::Physic::PhysicEngine* mPhysicsEngine;
|
||||||
|
|
||||||
MWRender::Player *mPlayer;
|
MWRender::Player *mPlayer;
|
||||||
MWRender::Debugging mDebugging;
|
|
||||||
|
MWRender::Debugging *mDebugging;
|
||||||
|
|
||||||
MWRender::LocalMap* mLocalMap;
|
MWRender::LocalMap* mLocalMap;
|
||||||
|
|
||||||
|
MWRender::Shadows* mShadows;
|
||||||
|
|
||||||
|
MWRender::ShaderHelper* mShaderHelper;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
308
apps/openmw/mwrender/shaderhelper.cpp
Normal file
308
apps/openmw/mwrender/shaderhelper.cpp
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
#include "shaderhelper.hpp"
|
||||||
|
#include "renderingmanager.hpp"
|
||||||
|
#include "shadows.hpp"
|
||||||
|
|
||||||
|
#include <OgreHighLevelGpuProgramManager.h>
|
||||||
|
#include <OgreHighLevelGpuProgram.h>
|
||||||
|
#include <OgreGpuProgramParams.h>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
using namespace Ogre;
|
||||||
|
using namespace MWRender;
|
||||||
|
|
||||||
|
ShaderHelper::ShaderHelper(RenderingManager* rend)
|
||||||
|
{
|
||||||
|
mRendering = rend;
|
||||||
|
applyShaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderHelper::applyShaders()
|
||||||
|
{
|
||||||
|
if (!Settings::Manager::getBool("shaders", "Objects")) return;
|
||||||
|
|
||||||
|
bool mrt = RenderingManager::useMRT();
|
||||||
|
bool shadows = Settings::Manager::getBool("enabled", "Shadows");
|
||||||
|
bool split = Settings::Manager::getBool("split", "Shadows");
|
||||||
|
|
||||||
|
// shader for normal rendering
|
||||||
|
createShader(mrt, shadows, split, "main");
|
||||||
|
|
||||||
|
// fallback shader without mrt and without shadows
|
||||||
|
// (useful for reflection and for minimap)
|
||||||
|
createShader(false, false, false, "main_fallback");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool split, const std::string& name)
|
||||||
|
{
|
||||||
|
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
|
||||||
|
|
||||||
|
const int numsplits = 3;
|
||||||
|
|
||||||
|
// the number of lights to support.
|
||||||
|
// when rendering an object, OGRE automatically picks the lights that are
|
||||||
|
// closest to the object being rendered. unfortunately this mechanism does
|
||||||
|
// not work perfectly for objects batched together (they will all use the same
|
||||||
|
// lights). to work around this, we are simply pushing the maximum number
|
||||||
|
// of lights here in order to minimize disappearing lights.
|
||||||
|
int num_lights = Settings::Manager::getInt("num lights", "Objects");
|
||||||
|
|
||||||
|
{
|
||||||
|
// vertex
|
||||||
|
HighLevelGpuProgramPtr vertex;
|
||||||
|
if (!mgr.getByName(name+"_vp").isNull())
|
||||||
|
mgr.remove(name+"_vp");
|
||||||
|
|
||||||
|
vertex = mgr.createProgram(name+"_vp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
|
"cg", GPT_VERTEX_PROGRAM);
|
||||||
|
vertex->setParameter("profiles", "vs_4_0 vs_2_x vp40 arbvp1");
|
||||||
|
vertex->setParameter("entry_point", "main_vp");
|
||||||
|
StringUtil::StrStreamType outStream;
|
||||||
|
outStream <<
|
||||||
|
"void main_vp( \n"
|
||||||
|
" float4 position : POSITION, \n"
|
||||||
|
" float4 normal : NORMAL, \n"
|
||||||
|
" float4 colour : COLOR, \n"
|
||||||
|
" in float2 uv : TEXCOORD0, \n"
|
||||||
|
" out float2 oUV : TEXCOORD0, \n"
|
||||||
|
" out float4 oPosition : POSITION, \n"
|
||||||
|
" out float4 oPositionObjSpace : TEXCOORD1, \n"
|
||||||
|
" out float4 oNormal : TEXCOORD2, \n"
|
||||||
|
" out float oDepth : TEXCOORD3, \n"
|
||||||
|
" out float4 oVertexColour : TEXCOORD4, \n";
|
||||||
|
if (shadows && !split) outStream <<
|
||||||
|
" out float4 oLightSpacePos0 : TEXCOORD5, \n"
|
||||||
|
" uniform float4x4 worldMatrix, \n"
|
||||||
|
" uniform float4x4 texViewProjMatrix0, \n";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i=0; i<numsplits; ++i)
|
||||||
|
{
|
||||||
|
outStream <<
|
||||||
|
" out float4 oLightSpacePos"<<i<<" : TEXCOORD"<<i+5<<", \n"
|
||||||
|
" uniform float4x4 texViewProjMatrix"<<i<<", \n";
|
||||||
|
}
|
||||||
|
outStream <<
|
||||||
|
" uniform float4x4 worldMatrix, \n";
|
||||||
|
}
|
||||||
|
outStream <<
|
||||||
|
" uniform float4x4 worldViewProj \n"
|
||||||
|
") \n"
|
||||||
|
"{ \n"
|
||||||
|
" oVertexColour = colour; \n"
|
||||||
|
" oUV = uv; \n"
|
||||||
|
" oNormal = normal; \n"
|
||||||
|
" oPosition = mul( worldViewProj, position ); \n"
|
||||||
|
" oDepth = oPosition.z; \n"
|
||||||
|
" oPositionObjSpace = position; \n";
|
||||||
|
if (shadows && !split) outStream <<
|
||||||
|
" oLightSpacePos0 = mul(texViewProjMatrix0, mul(worldMatrix, position)); \n";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outStream <<
|
||||||
|
" float4 wPos = mul(worldMatrix, position); \n";
|
||||||
|
for (int i=0; i<numsplits; ++i)
|
||||||
|
{
|
||||||
|
outStream <<
|
||||||
|
" oLightSpacePos"<<i<<" = mul(texViewProjMatrix"<<i<<", wPos); \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outStream <<
|
||||||
|
"}";
|
||||||
|
vertex->setSource(outStream.str());
|
||||||
|
vertex->load();
|
||||||
|
vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||||
|
if (shadows)
|
||||||
|
{
|
||||||
|
vertex->getDefaultParameters()->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX);
|
||||||
|
if (!split)
|
||||||
|
vertex->getDefaultParameters()->setNamedAutoConstant("texViewProjMatrix0", GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i=0; i<numsplits; ++i)
|
||||||
|
{
|
||||||
|
vertex->getDefaultParameters()->setNamedAutoConstant("texViewProjMatrix"+StringConverter::toString(i), GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// fragment
|
||||||
|
HighLevelGpuProgramPtr fragment;
|
||||||
|
if (!mgr.getByName(name+"_fp").isNull())
|
||||||
|
mgr.remove(name+"_fp");
|
||||||
|
|
||||||
|
fragment = mgr.createProgram(name+"_fp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
|
"cg", GPT_FRAGMENT_PROGRAM);
|
||||||
|
fragment->setParameter("profiles", "ps_4_0 ps_2_x fp40 arbfp1");
|
||||||
|
fragment->setParameter("entry_point", "main_fp");
|
||||||
|
StringUtil::StrStreamType outStream;
|
||||||
|
|
||||||
|
if (shadows) outStream <<
|
||||||
|
"float depthShadow(sampler2D shadowMap, float4 shadowMapPos, float2 offset) \n"
|
||||||
|
"{ \n"
|
||||||
|
" shadowMapPos /= shadowMapPos.w; \n"
|
||||||
|
" float3 o = float3(offset.xy, -offset.x) * 0.3f; \n"
|
||||||
|
" float c = (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy - o.xy).r) ? 1 : 0; // top left \n"
|
||||||
|
" c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy + o.xy).r) ? 1 : 0; // bottom right \n"
|
||||||
|
" c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy + o.zy).r) ? 1 : 0; // bottom left \n"
|
||||||
|
" c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy - o.zy).r) ? 1 : 0; // top right \n"
|
||||||
|
" return c / 4; \n"
|
||||||
|
"} \n";
|
||||||
|
|
||||||
|
outStream <<
|
||||||
|
"void main_fp( \n"
|
||||||
|
" in float2 uv : TEXCOORD0, \n"
|
||||||
|
" out float4 oColor : COLOR, \n"
|
||||||
|
" uniform sampler2D texture : register(s0), \n"
|
||||||
|
" float4 positionObjSpace : TEXCOORD1, \n"
|
||||||
|
" float4 normal : TEXCOORD2, \n"
|
||||||
|
" float iDepth : TEXCOORD3, \n"
|
||||||
|
" float4 vertexColour : TEXCOORD4, \n"
|
||||||
|
" uniform float4 fogColour, \n"
|
||||||
|
" uniform float4 fogParams, \n";
|
||||||
|
|
||||||
|
if (shadows) outStream <<
|
||||||
|
" uniform float4 shadowFar_fadeStart, \n";
|
||||||
|
|
||||||
|
if (shadows && !split) outStream <<
|
||||||
|
" uniform sampler2D shadowMap : register(s1), \n"
|
||||||
|
" float4 lightSpacePos0 : TEXCOORD5, \n"
|
||||||
|
" uniform float4 invShadowmapSize0, \n";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outStream <<
|
||||||
|
" uniform float4 pssmSplitPoints, \n";
|
||||||
|
for (int i=0; i<numsplits; ++i)
|
||||||
|
{
|
||||||
|
outStream <<
|
||||||
|
" uniform sampler2D shadowMap"<<i<<" : register(s"<<i+1<<"), \n"
|
||||||
|
" float4 lightSpacePos"<<i<<" : TEXCOORD"<<i+5<<", \n"
|
||||||
|
" uniform float4 invShadowmapSize"<<i<<", \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mrt) outStream <<
|
||||||
|
" out float4 oColor1 : COLOR1, \n"
|
||||||
|
" uniform float far, \n";
|
||||||
|
|
||||||
|
for (int i=0; i<num_lights; ++i)
|
||||||
|
{
|
||||||
|
outStream <<
|
||||||
|
" uniform float4 lightDiffuse"<<i<<", \n"
|
||||||
|
" uniform float4 lightPositionObjSpace"<<i<<", \n"
|
||||||
|
" uniform float4 lightAttenuation"<<i<<", \n";
|
||||||
|
}
|
||||||
|
outStream <<
|
||||||
|
" uniform float4 lightAmbient, \n"
|
||||||
|
" uniform float4 ambient, \n"
|
||||||
|
" uniform float4 diffuse, \n"
|
||||||
|
" uniform float4 emissive \n"
|
||||||
|
") \n"
|
||||||
|
"{ \n"
|
||||||
|
" float4 tex = tex2D(texture, uv); \n"
|
||||||
|
" float d; \n"
|
||||||
|
" float attn; \n"
|
||||||
|
" float3 lightDir; \n"
|
||||||
|
" float3 lightColour = float3(0, 0, 0); \n";
|
||||||
|
|
||||||
|
for (int i=0; i<num_lights; ++i)
|
||||||
|
{
|
||||||
|
outStream <<
|
||||||
|
" lightDir = lightPositionObjSpace"<<i<<".xyz - (positionObjSpace.xyz * lightPositionObjSpace"<<i<<".w); \n"
|
||||||
|
|
||||||
|
// pre-multiply light color with attenuation factor
|
||||||
|
" d = length( lightDir ); \n"
|
||||||
|
" attn = ( 1.0 / (( lightAttenuation"<<i<<".y ) + ( lightAttenuation"<<i<<".z * d ) + ( lightAttenuation"<<i<<".w * d * d ))); \n"
|
||||||
|
" lightDiffuse"<<i<<" *= attn; \n";
|
||||||
|
|
||||||
|
if (i == 0 && shadows)
|
||||||
|
{
|
||||||
|
outStream <<
|
||||||
|
" float shadow; \n";
|
||||||
|
if (!split) outStream <<
|
||||||
|
" shadow = depthShadow(shadowMap, lightSpacePos0, invShadowmapSize0.xy); \n";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int j=0; j<numsplits; ++j)
|
||||||
|
{
|
||||||
|
std::string channel;
|
||||||
|
if (j==0) channel = "x";
|
||||||
|
else if (j==1) channel = "y";
|
||||||
|
else if (j==2) channel = "z";
|
||||||
|
|
||||||
|
if (j==0)
|
||||||
|
outStream << " if (iDepth <= pssmSplitPoints." << channel << ") \n";
|
||||||
|
else if (j < numsplits - 1)
|
||||||
|
outStream << " else if (iDepth <= pssmSplitPoints." << channel << ") \n";
|
||||||
|
else
|
||||||
|
outStream << " else \n";
|
||||||
|
|
||||||
|
outStream <<
|
||||||
|
" { \n"
|
||||||
|
" shadow = depthShadow(shadowMap" << j << ", lightSpacePos" << j << ", invShadowmapSize" << j << ".xy); \n"
|
||||||
|
" } \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outStream <<
|
||||||
|
" float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \n"
|
||||||
|
" float fade = 1-((iDepth - shadowFar_fadeStart.y) / fadeRange); \n"
|
||||||
|
" shadow = (iDepth > shadowFar_fadeStart.x) ? 1 : ((iDepth > shadowFar_fadeStart.y) ? 1-((1-shadow)*fade) : shadow); \n"
|
||||||
|
" lightColour.xyz += shadow * lit(dot(normalize(lightDir), normalize(normal)), 0, 0).y * lightDiffuse"<<i<<".xyz;\n";
|
||||||
|
}
|
||||||
|
else outStream <<
|
||||||
|
" lightColour.xyz += lit(dot(normalize(lightDir), normalize(normal)), 0, 0).y * lightDiffuse"<<i<<".xyz;\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
outStream <<
|
||||||
|
" float3 lightingFinal = lightColour.xyz * diffuse.xyz * vertexColour.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n"
|
||||||
|
" float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n"
|
||||||
|
" oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour.xyz, fogValue); \n"
|
||||||
|
" oColor.a = tex.a * diffuse.a * vertexColour.a; \n";
|
||||||
|
|
||||||
|
if (mrt) outStream <<
|
||||||
|
" oColor1 = float4(iDepth / far, 0, 0, (oColor.a == 1)); \n"; // only write to MRT if alpha is 1
|
||||||
|
|
||||||
|
outStream <<
|
||||||
|
"}";
|
||||||
|
fragment->setSource(outStream.str());
|
||||||
|
fragment->load();
|
||||||
|
|
||||||
|
for (int i=0; i<num_lights; ++i)
|
||||||
|
{
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("lightPositionObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i);
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("lightDiffuse"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i);
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i);
|
||||||
|
}
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR);
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR);
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
|
||||||
|
|
||||||
|
if (shadows)
|
||||||
|
{
|
||||||
|
fragment->getDefaultParameters()->setNamedConstant("shadowFar_fadeStart", Vector4(mRendering->getShadows()->getShadowFar(), mRendering->getShadows()->getFadeStart()*mRendering->getShadows()->getShadowFar(), 0, 0));
|
||||||
|
for (int i=0; i < (split ? numsplits : 1); ++i)
|
||||||
|
{
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("invShadowmapSize" + StringConverter::toString(i), GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, i+1);
|
||||||
|
}
|
||||||
|
if (split)
|
||||||
|
{
|
||||||
|
Vector4 splitPoints;
|
||||||
|
const PSSMShadowCameraSetup::SplitPointList& splitPointList = mRendering->getShadows()->getPSSMSetup()->getSplitPoints();
|
||||||
|
// Populate from split point 1, not 0, since split 0 isn't useful (usually 0)
|
||||||
|
for (int i = 1; i < numsplits; ++i)
|
||||||
|
{
|
||||||
|
splitPoints[i-1] = splitPointList[i];
|
||||||
|
}
|
||||||
|
fragment->getDefaultParameters()->setNamedConstant("pssmSplitPoints", splitPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mrt)
|
||||||
|
fragment->getDefaultParameters()->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
|
||||||
|
}
|
||||||
|
}
|
29
apps/openmw/mwrender/shaderhelper.hpp
Normal file
29
apps/openmw/mwrender/shaderhelper.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef GAME_SHADERHELPER_H
|
||||||
|
#define GAME_SHADERHELPER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
class RenderingManager;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief manages the main shader
|
||||||
|
///
|
||||||
|
class ShaderHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderHelper(RenderingManager* rend);
|
||||||
|
|
||||||
|
void applyShaders();
|
||||||
|
///< apply new settings
|
||||||
|
|
||||||
|
private:
|
||||||
|
RenderingManager* mRendering;
|
||||||
|
|
||||||
|
void createShader(const bool mrt, const bool shadows, const bool split, const std::string& name);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
173
apps/openmw/mwrender/shadows.cpp
Normal file
173
apps/openmw/mwrender/shadows.cpp
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
#include "shadows.hpp"
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <openengine/ogre/renderer.hpp>
|
||||||
|
|
||||||
|
#include <OgreSceneManager.h>
|
||||||
|
#include <OgreColourValue.h>
|
||||||
|
#include <OgreShadowCameraSetupLiSPSM.h>
|
||||||
|
#include <OgreShadowCameraSetupPSSM.h>
|
||||||
|
#include <OgreHardwarePixelBuffer.h>
|
||||||
|
|
||||||
|
#include <OgreOverlayContainer.h>
|
||||||
|
#include <OgreOverlayManager.h>
|
||||||
|
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
|
||||||
|
using namespace Ogre;
|
||||||
|
using namespace MWRender;
|
||||||
|
|
||||||
|
Shadows::Shadows(OEngine::Render::OgreRenderer* rend) :
|
||||||
|
mShadowFar(1000), mFadeStart(0.9)
|
||||||
|
{
|
||||||
|
mRendering = rend;
|
||||||
|
mSceneMgr = mRendering->getScene();
|
||||||
|
recreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shadows::recreate()
|
||||||
|
{
|
||||||
|
bool enabled = Settings::Manager::getBool("enabled", "Shadows");
|
||||||
|
|
||||||
|
// Split shadow maps are currently disabled because the terrain cannot cope with them
|
||||||
|
// (Too many texture units) Solution would be a multi-pass terrain material
|
||||||
|
bool split = Settings::Manager::getBool("split", "Shadows");
|
||||||
|
//const bool split = false;
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
{
|
||||||
|
mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int texsize = Settings::Manager::getInt("texture size", "Shadows");
|
||||||
|
mSceneMgr->setShadowTextureSize(texsize);
|
||||||
|
|
||||||
|
mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED);
|
||||||
|
|
||||||
|
// no point light shadows, i'm afraid. might revisit this with Deferred Shading
|
||||||
|
mSceneMgr->setShadowTextureCountPerLightType(Light::LT_POINT, 0);
|
||||||
|
|
||||||
|
mSceneMgr->setShadowTextureCountPerLightType(Light::LT_DIRECTIONAL, split ? 3 : 1);
|
||||||
|
mSceneMgr->setShadowTextureCount(split ? 3 : 1);
|
||||||
|
|
||||||
|
mSceneMgr->setShadowTextureSelfShadow(true);
|
||||||
|
mSceneMgr->setShadowCasterRenderBackFaces(true);
|
||||||
|
mSceneMgr->setShadowTextureCasterMaterial("depth_shadow_caster");
|
||||||
|
mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R);
|
||||||
|
mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000);
|
||||||
|
|
||||||
|
mShadowFar = split ? Settings::Manager::getInt("split shadow distance", "Shadows") : Settings::Manager::getInt("shadow distance", "Shadows");
|
||||||
|
mSceneMgr->setShadowFarDistance(mShadowFar);
|
||||||
|
|
||||||
|
mFadeStart = Settings::Manager::getFloat("fade start", "Shadows");
|
||||||
|
|
||||||
|
ShadowCameraSetupPtr shadowCameraSetup;
|
||||||
|
if (split)
|
||||||
|
{
|
||||||
|
mPSSMSetup = new PSSMShadowCameraSetup();
|
||||||
|
mPSSMSetup->setSplitPadding(5);
|
||||||
|
mPSSMSetup->calculateSplitPoints(3, mRendering->getCamera()->getNearClipDistance(), mShadowFar);
|
||||||
|
|
||||||
|
const Real adjustFactors[3] = {64, 64, 64};
|
||||||
|
for (int i=0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
mPSSMSetup->setOptimalAdjustFactor(i, adjustFactors[i]);
|
||||||
|
/*if (i==0)
|
||||||
|
mSceneMgr->setShadowTextureConfig(i, texsize, texsize, Ogre::PF_FLOAT32_R);
|
||||||
|
else if (i ==1)
|
||||||
|
mSceneMgr->setShadowTextureConfig(i, texsize/2, texsize/2, Ogre::PF_FLOAT32_R);
|
||||||
|
else if (i ==2)
|
||||||
|
mSceneMgr->setShadowTextureConfig(i, texsize/4, texsize/4, Ogre::PF_FLOAT32_R);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowCameraSetup = ShadowCameraSetupPtr(mPSSMSetup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LiSPSMShadowCameraSetup* lispsmSetup = new LiSPSMShadowCameraSetup();
|
||||||
|
lispsmSetup->setOptimalAdjustFactor(2);
|
||||||
|
//lispsmSetup->setCameraLightDirectionThreshold(Degree(0));
|
||||||
|
//lispsmSetup->setUseAggressiveFocusRegion(false);
|
||||||
|
shadowCameraSetup = ShadowCameraSetupPtr(lispsmSetup);
|
||||||
|
}
|
||||||
|
mSceneMgr->setShadowCameraSetup(shadowCameraSetup);
|
||||||
|
|
||||||
|
// Set visibility mask for the shadow render textures
|
||||||
|
int visibilityMask = RV_Actors * Settings::Manager::getBool("actor shadows", "Shadows")
|
||||||
|
+ (RV_Statics + RV_StaticsSmall) * Settings::Manager::getBool("statics shadows", "Shadows")
|
||||||
|
+ RV_Misc * Settings::Manager::getBool("misc shadows", "Shadows");
|
||||||
|
|
||||||
|
for (int i = 0; i < (split ? 3 : 1); ++i)
|
||||||
|
{
|
||||||
|
TexturePtr shadowTexture = mSceneMgr->getShadowTexture(i);
|
||||||
|
Viewport* vp = shadowTexture->getBuffer()->getRenderTarget()->getViewport(0);
|
||||||
|
vp->setVisibilityMask(visibilityMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
// --------------------------- Debug overlays to display the content of shadow maps -----------------------------------
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
OverlayManager& mgr = OverlayManager::getSingleton();
|
||||||
|
Overlay* overlay;
|
||||||
|
|
||||||
|
// destroy if already exists
|
||||||
|
if (overlay = mgr.getByName("DebugOverlay"))
|
||||||
|
mgr.destroy(overlay);
|
||||||
|
|
||||||
|
overlay = mgr.create("DebugOverlay");
|
||||||
|
for (size_t i = 0; i < (split ? 3 : 1); ++i) {
|
||||||
|
TexturePtr tex = mRendering->getScene()->getShadowTexture(i);
|
||||||
|
|
||||||
|
// Set up a debug panel to display the shadow
|
||||||
|
|
||||||
|
if (MaterialManager::getSingleton().resourceExists("Ogre/DebugTexture" + StringConverter::toString(i)))
|
||||||
|
MaterialManager::getSingleton().remove("Ogre/DebugTexture" + StringConverter::toString(i));
|
||||||
|
MaterialPtr debugMat = MaterialManager::getSingleton().create(
|
||||||
|
"Ogre/DebugTexture" + StringConverter::toString(i),
|
||||||
|
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||||
|
|
||||||
|
debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
|
||||||
|
TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName());
|
||||||
|
t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
|
||||||
|
|
||||||
|
OverlayContainer* debugPanel;
|
||||||
|
|
||||||
|
// destroy container if exists
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (debugPanel =
|
||||||
|
static_cast<OverlayContainer*>(
|
||||||
|
mgr.getOverlayElement("Ogre/DebugTexPanel" + StringConverter::toString(i)
|
||||||
|
)))
|
||||||
|
mgr.destroyOverlayElement(debugPanel);
|
||||||
|
}
|
||||||
|
catch (Ogre::Exception&) {}
|
||||||
|
|
||||||
|
debugPanel = (OverlayContainer*)
|
||||||
|
(OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugTexPanel" + StringConverter::toString(i)));
|
||||||
|
debugPanel->_setPosition(0.8, i*0.25);
|
||||||
|
debugPanel->_setDimensions(0.2, 0.24);
|
||||||
|
debugPanel->setMaterialName(debugMat->getName());
|
||||||
|
debugPanel->show();
|
||||||
|
overlay->add2D(debugPanel);
|
||||||
|
overlay->show();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
PSSMShadowCameraSetup* Shadows::getPSSMSetup()
|
||||||
|
{
|
||||||
|
return mPSSMSetup;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Shadows::getShadowFar() const
|
||||||
|
{
|
||||||
|
return mShadowFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Shadows::getFadeStart() const
|
||||||
|
{
|
||||||
|
return mFadeStart;
|
||||||
|
}
|
39
apps/openmw/mwrender/shadows.hpp
Normal file
39
apps/openmw/mwrender/shadows.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef GAME_SHADOWS_H
|
||||||
|
#define GAME_SHADOWS_H
|
||||||
|
|
||||||
|
// forward declares
|
||||||
|
namespace Ogre
|
||||||
|
{
|
||||||
|
class SceneManager;
|
||||||
|
class PSSMShadowCameraSetup;
|
||||||
|
}
|
||||||
|
namespace OEngine{
|
||||||
|
namespace Render{
|
||||||
|
class OgreRenderer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
class Shadows
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Shadows(OEngine::Render::OgreRenderer* rend);
|
||||||
|
|
||||||
|
void recreate();
|
||||||
|
|
||||||
|
Ogre::PSSMShadowCameraSetup* getPSSMSetup();
|
||||||
|
float getShadowFar() const;
|
||||||
|
float getFadeStart() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OEngine::Render::OgreRenderer* mRendering;
|
||||||
|
Ogre::SceneManager* mSceneMgr;
|
||||||
|
|
||||||
|
Ogre::PSSMShadowCameraSetup* mPSSMSetup;
|
||||||
|
float mShadowFar;
|
||||||
|
float mFadeStart;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include "../mwworld/environment.hpp"
|
#include "../mwworld/environment.hpp"
|
||||||
#include "../mwworld/world.hpp"
|
#include "../mwworld/world.hpp"
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
#include "renderingmanager.hpp"
|
||||||
|
|
||||||
using namespace MWRender;
|
using namespace MWRender;
|
||||||
using namespace Ogre;
|
using namespace Ogre;
|
||||||
|
@ -30,7 +32,7 @@ BillboardObject::BillboardObject()
|
||||||
|
|
||||||
void BillboardObject::setVisible(const bool visible)
|
void BillboardObject::setVisible(const bool visible)
|
||||||
{
|
{
|
||||||
mNode->setVisible(visible);
|
mBBSet->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BillboardObject::setSize(const float size)
|
void BillboardObject::setSize(const float size)
|
||||||
|
@ -59,6 +61,11 @@ Vector3 BillboardObject::getPosition() const
|
||||||
return Vector3(p.x, -p.z, p.y);
|
return Vector3(p.x, -p.z, p.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BillboardObject::setVisibilityFlags(int flags)
|
||||||
|
{
|
||||||
|
mBBSet->setVisibilityFlags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
void BillboardObject::setColour(const ColourValue& pColour)
|
void BillboardObject::setColour(const ColourValue& pColour)
|
||||||
{
|
{
|
||||||
mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour);
|
mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour);
|
||||||
|
@ -88,13 +95,14 @@ void BillboardObject::init(const String& textureName,
|
||||||
/// \todo These billboards are not 100% correct, might want to revisit them later
|
/// \todo These billboards are not 100% correct, might want to revisit them later
|
||||||
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
|
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
|
||||||
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
|
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
|
||||||
mBBSet->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+2);
|
|
||||||
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
|
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
|
||||||
mBBSet->setCommonDirection( -position.normalisedCopy() );
|
mBBSet->setCommonDirection( -position.normalisedCopy() );
|
||||||
|
mBBSet->setVisibilityFlags(RV_Sky);
|
||||||
mNode = rootNode->createChildSceneNode();
|
mNode = rootNode->createChildSceneNode();
|
||||||
mNode->setPosition(finalPosition);
|
mNode->setPosition(finalPosition);
|
||||||
mNode->attachObject(mBBSet);
|
mNode->attachObject(mBBSet);
|
||||||
mBBSet->createBillboard(0,0,0);
|
mBBSet->createBillboard(0,0,0);
|
||||||
|
mBBSet->setCastShadows(false);
|
||||||
|
|
||||||
mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||||
mMaterial->removeAllTechniques();
|
mMaterial->removeAllTechniques();
|
||||||
|
@ -108,6 +116,65 @@ void BillboardObject::init(const String& textureName,
|
||||||
p->createTextureUnitState(textureName);
|
p->createTextureUnitState(textureName);
|
||||||
mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount));
|
mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount));
|
||||||
|
|
||||||
|
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
|
||||||
|
HighLevelGpuProgramPtr vshader;
|
||||||
|
if (mgr.resourceExists("BBO_VP"))
|
||||||
|
vshader = mgr.getByName("BBO_VP");
|
||||||
|
else
|
||||||
|
vshader = mgr.createProgram("BBO_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM);
|
||||||
|
vshader->setParameter("profiles", "vs_2_x arbvp1");
|
||||||
|
vshader->setParameter("entry_point", "main_vp");
|
||||||
|
StringUtil::StrStreamType outStream;
|
||||||
|
outStream <<
|
||||||
|
"void main_vp( \n"
|
||||||
|
" float4 position : POSITION, \n"
|
||||||
|
" in float2 uv : TEXCOORD0, \n"
|
||||||
|
" out float2 oUV : TEXCOORD0, \n"
|
||||||
|
" out float4 oPosition : POSITION, \n"
|
||||||
|
" uniform float4x4 worldViewProj \n"
|
||||||
|
") \n"
|
||||||
|
"{ \n"
|
||||||
|
" oUV = uv; \n"
|
||||||
|
" oPosition = mul( worldViewProj, position ); \n"
|
||||||
|
"}";
|
||||||
|
vshader->setSource(outStream.str());
|
||||||
|
vshader->load();
|
||||||
|
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||||
|
mMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
|
||||||
|
|
||||||
|
HighLevelGpuProgramPtr fshader;
|
||||||
|
if (mgr.resourceExists("BBO_FP"))
|
||||||
|
fshader = mgr.getByName("BBO_FP");
|
||||||
|
else
|
||||||
|
fshader = mgr.createProgram("BBO_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_FRAGMENT_PROGRAM);
|
||||||
|
|
||||||
|
fshader->setParameter("profiles", "ps_2_x arbfp1");
|
||||||
|
fshader->setParameter("entry_point", "main_fp");
|
||||||
|
StringUtil::StrStreamType outStream2;
|
||||||
|
outStream2 <<
|
||||||
|
"void main_fp( \n"
|
||||||
|
" in float2 uv : TEXCOORD0, \n"
|
||||||
|
" out float4 oColor : COLOR, \n";
|
||||||
|
if (RenderingManager::useMRT()) outStream2 <<
|
||||||
|
" out float4 oColor1 : COLOR1, \n";
|
||||||
|
outStream2 <<
|
||||||
|
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||||
|
" uniform float4 diffuse, \n"
|
||||||
|
" uniform float4 emissive \n"
|
||||||
|
") \n"
|
||||||
|
"{ \n"
|
||||||
|
" float4 tex = tex2D(texture, uv); \n"
|
||||||
|
" oColor = float4(emissive.xyz,1) * tex * float4(1,1,1,diffuse.a); \n";
|
||||||
|
if (RenderingManager::useMRT()) outStream2 <<
|
||||||
|
" oColor1 = float4(1, 0, 0, 1); \n";
|
||||||
|
outStream2 <<
|
||||||
|
"}";
|
||||||
|
fshader->setSource(outStream2.str());
|
||||||
|
fshader->load();
|
||||||
|
fshader->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
||||||
|
fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||||
|
mMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName());
|
||||||
|
|
||||||
bodyCount++;
|
bodyCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +223,10 @@ Moon::Moon( const String& textureName,
|
||||||
outStream2 <<
|
outStream2 <<
|
||||||
"void main_fp( \n"
|
"void main_fp( \n"
|
||||||
" in float2 uv : TEXCOORD0, \n"
|
" in float2 uv : TEXCOORD0, \n"
|
||||||
" out float4 oColor : COLOR, \n"
|
" out float4 oColor : COLOR, \n";
|
||||||
|
if (RenderingManager::useMRT()) outStream2 <<
|
||||||
|
" out float4 oColor1 : COLOR1, \n";
|
||||||
|
outStream2 <<
|
||||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||||
" uniform float4 skyColour, \n"
|
" uniform float4 skyColour, \n"
|
||||||
" uniform float4 diffuse, \n"
|
" uniform float4 diffuse, \n"
|
||||||
|
@ -164,7 +234,10 @@ Moon::Moon( const String& textureName,
|
||||||
") \n"
|
") \n"
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" float4 tex = tex2D(texture, uv); \n"
|
" float4 tex = tex2D(texture, uv); \n"
|
||||||
" oColor = float4(emissive.xyz,1) * tex; \n"
|
" oColor = float4(emissive.xyz,1) * tex; \n";
|
||||||
|
if (RenderingManager::useMRT()) outStream2 <<
|
||||||
|
" oColor1 = float4(1, 0, 0, 1); \n";
|
||||||
|
outStream2 <<
|
||||||
// use a circle for the alpha (compute UV distance to center)
|
// use a circle for the alpha (compute UV distance to center)
|
||||||
// looks a bit bad because its not filtered on the edges,
|
// looks a bit bad because its not filtered on the edges,
|
||||||
// but it's cheaper than a seperate alpha texture.
|
// but it's cheaper than a seperate alpha texture.
|
||||||
|
@ -254,7 +327,7 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType)
|
||||||
// Get a pointer to the vertex colour
|
// Get a pointer to the vertex colour
|
||||||
ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex );
|
ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex );
|
||||||
|
|
||||||
unsigned char alpha;
|
unsigned char alpha=0;
|
||||||
if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row
|
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)
|
else if (meshType == 1)
|
||||||
{
|
{
|
||||||
|
@ -292,16 +365,49 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType)
|
||||||
ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock();
|
ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environment* env) :
|
SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environment* env)
|
||||||
mGlareFade(0), mGlareEnabled(false)
|
: 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();
|
mViewport = pCamera->getViewport();
|
||||||
mSceneMgr = pMwRoot->getCreator();
|
mSceneMgr = pMwRoot->getCreator();
|
||||||
mRootNode = pCamera->getParentSceneNode()->createChildSceneNode();
|
mRootNode = pCamera->getParentSceneNode()->createChildSceneNode();
|
||||||
mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates
|
mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates
|
||||||
mRootNode->setInheritOrientation(false);
|
mRootNode->setInheritOrientation(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkyManager::create()
|
||||||
|
{
|
||||||
/// \todo preload all the textures and meshes that are used for sky rendering
|
/// \todo preload all the textures and meshes that are used for sky rendering
|
||||||
|
|
||||||
// Create overlay used for thunderstorm
|
// Create overlay used for thunderstorm
|
||||||
|
@ -324,15 +430,17 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
|
|
||||||
mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode);
|
mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode);
|
||||||
mSecunda->setType(Moon::Type_Secunda);
|
mSecunda->setType(Moon::Type_Secunda);
|
||||||
mSecunda->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+4);
|
mSecunda->setRenderQueue(RQG_SkiesEarly+4);
|
||||||
|
|
||||||
mMasser = new Moon("textures\\tx_masser_full.dds", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode);
|
mMasser = new Moon("textures\\tx_masser_full.dds", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode);
|
||||||
mMasser->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+3);
|
mMasser->setRenderQueue(RQG_SkiesEarly+3);
|
||||||
mMasser->setType(Moon::Type_Masser);
|
mMasser->setType(Moon::Type_Masser);
|
||||||
|
|
||||||
mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode);
|
mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode);
|
||||||
|
mSun->setRenderQueue(RQG_SkiesEarly+4);
|
||||||
mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode);
|
mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode);
|
||||||
mSunGlare->setRenderQueue(RENDER_QUEUE_SKIES_LATE);
|
mSunGlare->setRenderQueue(RQG_SkiesLate);
|
||||||
|
mSunGlare->setVisibilityFlags(RV_Glare);
|
||||||
|
|
||||||
|
|
||||||
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
|
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
|
||||||
|
@ -341,7 +449,9 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
/// \todo sky_night_02.nif (available in Bloodmoon)
|
/// \todo sky_night_02.nif (available in Bloodmoon)
|
||||||
MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif");
|
MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif");
|
||||||
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
|
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
|
||||||
night1_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+1);
|
night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1);
|
||||||
|
night1_ent->setVisibilityFlags(RV_Sky);
|
||||||
|
night1_ent->setCastShadows(false);
|
||||||
|
|
||||||
mAtmosphereNight = mRootNode->createChildSceneNode();
|
mAtmosphereNight = mRootNode->createChildSceneNode();
|
||||||
mAtmosphereNight->attachObject(night1_ent);
|
mAtmosphereNight->attachObject(night1_ent);
|
||||||
|
@ -379,7 +489,10 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
outStream5 <<
|
outStream5 <<
|
||||||
"void main_fp( \n"
|
"void main_fp( \n"
|
||||||
" in float2 uv : TEXCOORD0, \n"
|
" in float2 uv : TEXCOORD0, \n"
|
||||||
" out float4 oColor : COLOR, \n"
|
" out float4 oColor : COLOR, \n";
|
||||||
|
if (RenderingManager::useMRT()) outStream5 <<
|
||||||
|
" out float4 oColor1 : COLOR1, \n";
|
||||||
|
outStream5 <<
|
||||||
" in float fade : TEXCOORD1, \n"
|
" in float fade : TEXCOORD1, \n"
|
||||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||||
" uniform float opacity, \n"
|
" uniform float opacity, \n"
|
||||||
|
@ -387,7 +500,10 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
" uniform float4 emissive \n"
|
" uniform float4 emissive \n"
|
||||||
") \n"
|
") \n"
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n"
|
" oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n";
|
||||||
|
if (RenderingManager::useMRT()) outStream5 <<
|
||||||
|
" oColor1 = float4(1, 0, 0, 1); \n";
|
||||||
|
outStream5 <<
|
||||||
"}";
|
"}";
|
||||||
stars_fp->setSource(outStream5.str());
|
stars_fp->setSource(outStream5.str());
|
||||||
stars_fp->load();
|
stars_fp->load();
|
||||||
|
@ -411,10 +527,12 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
// Atmosphere (day)
|
// Atmosphere (day)
|
||||||
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
|
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
|
||||||
Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif");
|
Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif");
|
||||||
|
atmosphere_ent->setCastShadows(false);
|
||||||
|
|
||||||
ModVertexAlpha(atmosphere_ent, 0);
|
ModVertexAlpha(atmosphere_ent, 0);
|
||||||
|
|
||||||
atmosphere_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY);
|
atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly);
|
||||||
|
atmosphere_ent->setVisibilityFlags(RV_Sky);
|
||||||
mAtmosphereDay = mRootNode->createChildSceneNode();
|
mAtmosphereDay = mRootNode->createChildSceneNode();
|
||||||
mAtmosphereDay->attachObject(atmosphere_ent);
|
mAtmosphereDay->attachObject(atmosphere_ent);
|
||||||
mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial();
|
mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial();
|
||||||
|
@ -432,29 +550,56 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
" float4 position : POSITION, \n"
|
" float4 position : POSITION, \n"
|
||||||
" in float4 color : COLOR, \n"
|
" in float4 color : COLOR, \n"
|
||||||
" out float4 oPosition : POSITION, \n"
|
" out float4 oPosition : POSITION, \n"
|
||||||
" out float4 oColor : COLOR, \n"
|
" out float4 oVertexColor : TEXCOORD0, \n"
|
||||||
" uniform float4 emissive, \n"
|
|
||||||
" uniform float4x4 worldViewProj \n"
|
" uniform float4x4 worldViewProj \n"
|
||||||
") \n"
|
") \n"
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" oPosition = mul( worldViewProj, position ); \n"
|
" oPosition = mul( worldViewProj, position ); \n"
|
||||||
" oColor = color * emissive; \n"
|
" oVertexColor = color; \n"
|
||||||
"}";
|
"}";
|
||||||
vshader->setSource(outStream.str());
|
vshader->setSource(outStream.str());
|
||||||
vshader->load();
|
vshader->load();
|
||||||
|
|
||||||
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
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)->setVertexProgram(vshader->getName());
|
||||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram("");
|
|
||||||
|
HighLevelGpuProgramPtr fshader = mgr.createProgram("Atmosphere_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
|
"cg", GPT_FRAGMENT_PROGRAM);
|
||||||
|
|
||||||
|
fshader->setParameter("profiles", "ps_2_x arbfp1");
|
||||||
|
fshader->setParameter("entry_point", "main_fp");
|
||||||
|
|
||||||
|
StringUtil::StrStreamType _outStream;
|
||||||
|
_outStream <<
|
||||||
|
"void main_fp( \n"
|
||||||
|
" in float4 iVertexColor : TEXCOORD0, \n"
|
||||||
|
" out float4 oColor : COLOR, \n";
|
||||||
|
if (RenderingManager::useMRT()) _outStream <<
|
||||||
|
" out float4 oColor1 : COLOR1, \n";
|
||||||
|
_outStream <<
|
||||||
|
" uniform float4 emissive \n"
|
||||||
|
") \n"
|
||||||
|
"{ \n"
|
||||||
|
" oColor = iVertexColor * emissive; \n";
|
||||||
|
if (RenderingManager::useMRT()) _outStream <<
|
||||||
|
" oColor1 = float4(1, 0, 0, 1); \n";
|
||||||
|
_outStream <<
|
||||||
|
"}";
|
||||||
|
fshader->setSource(_outStream.str());
|
||||||
|
fshader->load();
|
||||||
|
|
||||||
|
fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||||
|
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName());
|
||||||
|
|
||||||
// Clouds
|
// Clouds
|
||||||
NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif");
|
NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif");
|
||||||
Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif");
|
Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif");
|
||||||
clouds_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+5);
|
clouds_ent->setVisibilityFlags(RV_Sky);
|
||||||
|
clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5);
|
||||||
SceneNode* clouds_node = mRootNode->createChildSceneNode();
|
SceneNode* clouds_node = mRootNode->createChildSceneNode();
|
||||||
clouds_node->attachObject(clouds_ent);
|
clouds_node->attachObject(clouds_ent);
|
||||||
mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial();
|
mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial();
|
||||||
|
clouds_ent->setCastShadows(false);
|
||||||
|
|
||||||
// Clouds vertex shader
|
// Clouds vertex shader
|
||||||
HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
|
@ -491,8 +636,11 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
outStream2 <<
|
outStream2 <<
|
||||||
"void main_fp( \n"
|
"void main_fp( \n"
|
||||||
" in float2 uv : TEXCOORD0, \n"
|
" in float2 uv : TEXCOORD0, \n"
|
||||||
" out float4 oColor : COLOR, \n"
|
|
||||||
" in float4 color : TEXCOORD1, \n"
|
" in float4 color : TEXCOORD1, \n"
|
||||||
|
" out float4 oColor : COLOR, \n";
|
||||||
|
if (RenderingManager::useMRT()) outStream2 <<
|
||||||
|
" out float4 oColor1 : COLOR1, \n";
|
||||||
|
outStream2 <<
|
||||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||||
" uniform sampler2D secondTexture : TEXUNIT1, \n"
|
" uniform sampler2D secondTexture : TEXUNIT1, \n"
|
||||||
" uniform float transitionFactor, \n"
|
" uniform float transitionFactor, \n"
|
||||||
|
@ -502,9 +650,12 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
" uniform float4 emissive \n"
|
" uniform float4 emissive \n"
|
||||||
") \n"
|
") \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"
|
" float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n"
|
||||||
" oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n"
|
" oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n";
|
||||||
|
if (RenderingManager::useMRT()) outStream2 <<
|
||||||
|
" oColor1 = float4(1, 0, 0, 1); \n";
|
||||||
|
outStream2 <<
|
||||||
"}";
|
"}";
|
||||||
mCloudFragmentShader->setSource(outStream2.str());
|
mCloudFragmentShader->setSource(outStream2.str());
|
||||||
mCloudFragmentShader->load();
|
mCloudFragmentShader->load();
|
||||||
|
@ -530,7 +681,11 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||||
mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||||
|
|
||||||
|
mCloudMaterial->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
|
||||||
|
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("textures\\tx_sky_cloudy.dds");
|
||||||
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("");
|
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("");
|
||||||
|
|
||||||
|
mCreated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkyManager::~SkyManager()
|
SkyManager::~SkyManager()
|
||||||
|
@ -543,11 +698,13 @@ SkyManager::~SkyManager()
|
||||||
|
|
||||||
int SkyManager::getMasserPhase() const
|
int SkyManager::getMasserPhase() const
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return 0;
|
||||||
return mMasser->getPhaseInt();
|
return mMasser->getPhaseInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
int SkyManager::getSecundaPhase() const
|
int SkyManager::getSecundaPhase() const
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return 0;
|
||||||
return mSecunda->getPhaseInt();
|
return mSecunda->getPhaseInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,10 +719,23 @@ void SkyManager::update(float duration)
|
||||||
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||||
mSecunda->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)
|
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();
|
Vector3 sun = mSunGlare->getPosition();
|
||||||
sun = Vector3(sun.x, sun.z, -sun.y);
|
sun = Vector3(sun.x, sun.z, -sun.y);
|
||||||
Vector3 cam = mViewport->getCamera()->getRealDirection();
|
Vector3 cam = mViewport->getCamera()->getRealDirection();
|
||||||
|
@ -573,21 +743,10 @@ void SkyManager::update(float duration)
|
||||||
float val = 1- (angle.valueDegrees() / 180.f);
|
float val = 1- (angle.valueDegrees() / 180.f);
|
||||||
val = (val*val*val*val)*2;
|
val = (val*val*val*val)*2;
|
||||||
|
|
||||||
if (mGlareEnabled)
|
mSunGlare->setSize(val * mGlareFade);
|
||||||
{
|
|
||||||
mGlareFade += duration*3;
|
|
||||||
if (mGlareFade > 1) mGlareFade = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mGlareFade -= duration*3;
|
|
||||||
if (mGlareFade < 0.3) mGlareFade = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSunGlare->setSize(val * (mGlareFade));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mSunGlare->setVisible(mGlareFade>0 && mSunEnabled);
|
mSunGlare->setVisible(mSunEnabled);
|
||||||
mSun->setVisible(mSunEnabled);
|
mSun->setVisible(mSunEnabled);
|
||||||
mMasser->setVisible(mMasserEnabled);
|
mMasser->setVisible(mMasserEnabled);
|
||||||
mSecunda->setVisible(mSecundaEnabled);
|
mSecunda->setVisible(mSecundaEnabled);
|
||||||
|
@ -598,6 +757,9 @@ void SkyManager::update(float duration)
|
||||||
|
|
||||||
void SkyManager::enable()
|
void SkyManager::enable()
|
||||||
{
|
{
|
||||||
|
if (!mCreated)
|
||||||
|
create();
|
||||||
|
|
||||||
mRootNode->setVisible(true);
|
mRootNode->setVisible(true);
|
||||||
mEnabled = true;
|
mEnabled = true;
|
||||||
}
|
}
|
||||||
|
@ -610,17 +772,20 @@ void SkyManager::disable()
|
||||||
|
|
||||||
void SkyManager::setMoonColour (bool red)
|
void SkyManager::setMoonColour (bool red)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784)
|
mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784)
|
||||||
: ColourValue(1.0, 1.0, 1.0));
|
: ColourValue(1.0, 1.0, 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setCloudsOpacity(float opacity)
|
void SkyManager::setCloudsOpacity(float opacity)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity));
|
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
if (mClouds != weather.mCloudTexture)
|
if (mClouds != weather.mCloudTexture)
|
||||||
{
|
{
|
||||||
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture);
|
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture);
|
||||||
|
@ -689,19 +854,21 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
||||||
else
|
else
|
||||||
strength = 1.f;
|
strength = 1.f;
|
||||||
|
|
||||||
mSunGlare->setVisibility(weather.mGlareView * strength);
|
mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength);
|
||||||
mSun->setVisibility(strength);
|
|
||||||
|
mSun->setVisibility(weather.mGlareView * strength);
|
||||||
|
|
||||||
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
|
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setGlare(bool glare)
|
void SkyManager::setGlare(const float glare)
|
||||||
{
|
{
|
||||||
mGlareEnabled = glare;
|
mGlare = glare;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 SkyManager::getRealSunPos()
|
Vector3 SkyManager::getRealSunPos()
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return Vector3(0,0,0);
|
||||||
return mSun->getNode()->_getDerivedPosition();
|
return mSun->getNode()->_getDerivedPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,17 +884,20 @@ void SkyManager::sunDisable()
|
||||||
|
|
||||||
void SkyManager::setSunDirection(const Vector3& direction)
|
void SkyManager::setSunDirection(const Vector3& direction)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
mSun->setPosition(direction);
|
mSun->setPosition(direction);
|
||||||
mSunGlare->setPosition(direction);
|
mSunGlare->setPosition(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setMasserDirection(const Vector3& direction)
|
void SkyManager::setMasserDirection(const Vector3& direction)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
mMasser->setPosition(direction);
|
mMasser->setPosition(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setSecundaDirection(const Vector3& direction)
|
void SkyManager::setSecundaDirection(const Vector3& direction)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
mSecunda->setPosition(direction);
|
mSecunda->setPosition(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,6 +923,7 @@ void SkyManager::secundaDisable()
|
||||||
|
|
||||||
void SkyManager::setThunder(const float factor)
|
void SkyManager::setThunder(const float factor)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
if (factor > 0.f)
|
if (factor > 0.f)
|
||||||
{
|
{
|
||||||
mThunderOverlay->show();
|
mThunderOverlay->show();
|
||||||
|
@ -764,11 +935,13 @@ void SkyManager::setThunder(const float factor)
|
||||||
|
|
||||||
void SkyManager::setMasserFade(const float fade)
|
void SkyManager::setMasserFade(const float fade)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
mMasser->setVisibility(fade);
|
mMasser->setVisibility(fade);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setSecundaFade(const float fade)
|
void SkyManager::setSecundaFade(const float fade)
|
||||||
{
|
{
|
||||||
|
if (!mCreated) return;
|
||||||
mSecunda->setVisibility(fade);
|
mSecunda->setVisibility(fade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,3 +955,24 @@ void SkyManager::setDate(int day, int month)
|
||||||
mDay = day;
|
mDay = day;
|
||||||
mMonth = month;
|
mMonth = month;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ogre::SceneNode* SkyManager::getSunNode()
|
||||||
|
{
|
||||||
|
if (!mCreated) return 0;
|
||||||
|
return mSun->getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkyManager::setSkyPosition(const Ogre::Vector3& position)
|
||||||
|
{
|
||||||
|
mRootNode->_setDerivedPosition(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkyManager::resetSkyPosition()
|
||||||
|
{
|
||||||
|
mRootNode->setPosition(0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkyManager::scaleSky(float scale)
|
||||||
|
{
|
||||||
|
mRootNode->setScale(scale, scale, scale);
|
||||||
|
}
|
||||||
|
|
|
@ -36,24 +36,25 @@ namespace MWRender
|
||||||
BillboardObject();
|
BillboardObject();
|
||||||
|
|
||||||
virtual ~BillboardObject() {}
|
virtual ~BillboardObject() {}
|
||||||
|
|
||||||
void setColour(const Ogre::ColourValue& pColour);
|
void setColour(const Ogre::ColourValue& pColour);
|
||||||
void setPosition(const Ogre::Vector3& pPosition);
|
void setPosition(const Ogre::Vector3& pPosition);
|
||||||
void setVisible(const bool visible);
|
void setVisible(const bool visible);
|
||||||
void setRenderQueue(unsigned int id);
|
void setRenderQueue(unsigned int id);
|
||||||
|
void setVisibilityFlags(int flags);
|
||||||
void setSize(const float size);
|
void setSize(const float size);
|
||||||
Ogre::Vector3 getPosition() const;
|
Ogre::Vector3 getPosition() const;
|
||||||
|
|
||||||
void setVisibility(const float visibility);
|
void setVisibility(const float visibility);
|
||||||
|
|
||||||
Ogre::SceneNode* getNode();
|
Ogre::SceneNode* getNode();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void init(const Ogre::String& textureName,
|
virtual void init(const Ogre::String& textureName,
|
||||||
const float size,
|
const float size,
|
||||||
const Ogre::Vector3& position,
|
const Ogre::Vector3& position,
|
||||||
Ogre::SceneNode* rootNode);
|
Ogre::SceneNode* rootNode);
|
||||||
|
|
||||||
Ogre::SceneNode* mNode;
|
Ogre::SceneNode* mNode;
|
||||||
Ogre::MaterialPtr mMaterial;
|
Ogre::MaterialPtr mMaterial;
|
||||||
Ogre::BillboardSet* mBBSet;
|
Ogre::BillboardSet* mBBSet;
|
||||||
|
@ -71,9 +72,9 @@ namespace MWRender
|
||||||
const Ogre::Vector3& position,
|
const Ogre::Vector3& position,
|
||||||
Ogre::SceneNode* rootNode
|
Ogre::SceneNode* rootNode
|
||||||
);
|
);
|
||||||
|
|
||||||
virtual ~Moon() {}
|
virtual ~Moon() {}
|
||||||
|
|
||||||
enum Phase
|
enum Phase
|
||||||
{
|
{
|
||||||
Phase_New = 0,
|
Phase_New = 0,
|
||||||
|
@ -85,20 +86,20 @@ namespace MWRender
|
||||||
Phase_WaningHalf,
|
Phase_WaningHalf,
|
||||||
Phase_WaningCrescent
|
Phase_WaningCrescent
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
Type_Masser = 0,
|
Type_Masser = 0,
|
||||||
Type_Secunda
|
Type_Secunda
|
||||||
};
|
};
|
||||||
|
|
||||||
void setPhase(const Phase& phase);
|
void setPhase(const Phase& phase);
|
||||||
void setType(const Type& type);
|
void setType(const Type& type);
|
||||||
void setSkyColour(const Ogre::ColourValue& colour);
|
void setSkyColour(const Ogre::ColourValue& colour);
|
||||||
|
|
||||||
Phase getPhase() const;
|
Phase getPhase() const;
|
||||||
unsigned int getPhaseInt() const;
|
unsigned int getPhaseInt() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type mType;
|
Type mType;
|
||||||
Phase mPhase;
|
Phase mPhase;
|
||||||
|
@ -109,61 +110,72 @@ namespace MWRender
|
||||||
public:
|
public:
|
||||||
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env);
|
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env);
|
||||||
~SkyManager();
|
~SkyManager();
|
||||||
|
|
||||||
void update(float duration);
|
void update(float duration);
|
||||||
|
|
||||||
|
void create();
|
||||||
|
///< no need to call this, automatically done on first enable()
|
||||||
|
|
||||||
void enable();
|
void enable();
|
||||||
|
|
||||||
void disable();
|
void disable();
|
||||||
|
|
||||||
void setHour (double hour);
|
void setHour (double hour);
|
||||||
///< will be called even when sky is disabled.
|
///< will be called even when sky is disabled.
|
||||||
|
|
||||||
void setDate (int day, int month);
|
void setDate (int day, int month);
|
||||||
///< will be called even when sky is disabled.
|
///< will be called even when sky is disabled.
|
||||||
|
|
||||||
int getMasserPhase() const;
|
int getMasserPhase() const;
|
||||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||||
/// 3 waxing or waning gibbous, 4 full moon
|
/// 3 waxing or waning gibbous, 4 full moon
|
||||||
|
|
||||||
int getSecundaPhase() const;
|
int getSecundaPhase() const;
|
||||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||||
/// 3 waxing or waning gibbous, 4 full moon
|
/// 3 waxing or waning gibbous, 4 full moon
|
||||||
|
|
||||||
void setMoonColour (bool red);
|
void setMoonColour (bool red);
|
||||||
///< change Secunda colour to red
|
///< change Secunda colour to red
|
||||||
|
|
||||||
void setCloudsOpacity(float opacity);
|
void setCloudsOpacity(float opacity);
|
||||||
///< change opacity of the clouds
|
///< change opacity of the clouds
|
||||||
|
|
||||||
void setWeather(const MWWorld::WeatherResult& weather);
|
void setWeather(const MWWorld::WeatherResult& weather);
|
||||||
|
|
||||||
|
Ogre::SceneNode* getSunNode();
|
||||||
|
|
||||||
void sunEnable();
|
void sunEnable();
|
||||||
|
|
||||||
void sunDisable();
|
void sunDisable();
|
||||||
|
|
||||||
void setSunDirection(const Ogre::Vector3& direction);
|
void setSunDirection(const Ogre::Vector3& direction);
|
||||||
|
|
||||||
void setMasserDirection(const Ogre::Vector3& direction);
|
void setMasserDirection(const Ogre::Vector3& direction);
|
||||||
|
|
||||||
void setSecundaDirection(const Ogre::Vector3& direction);
|
void setSecundaDirection(const Ogre::Vector3& direction);
|
||||||
|
|
||||||
void setMasserFade(const float fade);
|
void setMasserFade(const float fade);
|
||||||
|
|
||||||
void setSecundaFade(const float fade);
|
void setSecundaFade(const float fade);
|
||||||
|
|
||||||
void masserEnable();
|
void masserEnable();
|
||||||
void masserDisable();
|
void masserDisable();
|
||||||
|
|
||||||
void secundaEnable();
|
void secundaEnable();
|
||||||
void secundaDisable();
|
void secundaDisable();
|
||||||
|
|
||||||
void setThunder(const float factor);
|
void setThunder(const float factor);
|
||||||
|
|
||||||
void setGlare(bool glare);
|
void setGlare(const float glare);
|
||||||
Ogre::Vector3 getRealSunPos();
|
Ogre::Vector3 getRealSunPos();
|
||||||
|
|
||||||
|
void setSkyPosition(const Ogre::Vector3& position);
|
||||||
|
void resetSkyPosition();
|
||||||
|
void scaleSky(float scale);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool mCreated;
|
||||||
|
|
||||||
MWWorld::Environment* mEnvironment;
|
MWWorld::Environment* mEnvironment;
|
||||||
float mHour;
|
float mHour;
|
||||||
int mDay;
|
int mDay;
|
||||||
|
@ -173,21 +185,21 @@ namespace MWRender
|
||||||
BillboardObject* mSunGlare;
|
BillboardObject* mSunGlare;
|
||||||
Moon* mMasser;
|
Moon* mMasser;
|
||||||
Moon* mSecunda;
|
Moon* mSecunda;
|
||||||
|
|
||||||
Ogre::Viewport* mViewport;
|
Ogre::Viewport* mViewport;
|
||||||
Ogre::SceneNode* mRootNode;
|
Ogre::SceneNode* mRootNode;
|
||||||
Ogre::SceneManager* mSceneMgr;
|
Ogre::SceneManager* mSceneMgr;
|
||||||
|
|
||||||
Ogre::SceneNode* mAtmosphereDay;
|
Ogre::SceneNode* mAtmosphereDay;
|
||||||
Ogre::SceneNode* mAtmosphereNight;
|
Ogre::SceneNode* mAtmosphereNight;
|
||||||
|
|
||||||
Ogre::MaterialPtr mCloudMaterial;
|
Ogre::MaterialPtr mCloudMaterial;
|
||||||
Ogre::MaterialPtr mAtmosphereMaterial;
|
Ogre::MaterialPtr mAtmosphereMaterial;
|
||||||
|
|
||||||
Ogre::MaterialPtr mStarsMaterials[7];
|
Ogre::MaterialPtr mStarsMaterials[7];
|
||||||
|
|
||||||
Ogre::HighLevelGpuProgramPtr mCloudFragmentShader;
|
Ogre::HighLevelGpuProgramPtr mCloudFragmentShader;
|
||||||
|
|
||||||
// remember some settings so we don't have to apply them again if they didnt change
|
// remember some settings so we don't have to apply them again if they didnt change
|
||||||
Ogre::String mClouds;
|
Ogre::String mClouds;
|
||||||
Ogre::String mNextClouds;
|
Ogre::String mNextClouds;
|
||||||
|
@ -197,18 +209,18 @@ namespace MWRender
|
||||||
float mStarsOpacity;
|
float mStarsOpacity;
|
||||||
Ogre::ColourValue mCloudColour;
|
Ogre::ColourValue mCloudColour;
|
||||||
Ogre::ColourValue mSkyColour;
|
Ogre::ColourValue mSkyColour;
|
||||||
|
|
||||||
Ogre::Overlay* mThunderOverlay;
|
Ogre::Overlay* mThunderOverlay;
|
||||||
Ogre::TextureUnitState* mThunderTextureUnit;
|
Ogre::TextureUnitState* mThunderTextureUnit;
|
||||||
|
|
||||||
float mRemainingTransitionTime;
|
float mRemainingTransitionTime;
|
||||||
|
|
||||||
float mGlareFade;
|
float mGlare; // target
|
||||||
|
float mGlareFade; // actual
|
||||||
|
|
||||||
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
|
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
|
||||||
|
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
bool mGlareEnabled;
|
|
||||||
bool mSunEnabled;
|
bool mSunEnabled;
|
||||||
bool mMasserEnabled;
|
bool mMasserEnabled;
|
||||||
bool mSecundaEnabled;
|
bool mSecundaEnabled;
|
||||||
|
|
531
apps/openmw/mwrender/terrain.cpp
Normal file
531
apps/openmw/mwrender/terrain.cpp
Normal file
|
@ -0,0 +1,531 @@
|
||||||
|
#include <OgreTerrain.h>
|
||||||
|
#include <OgreTerrainGroup.h>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
|
#include "../mwworld/world.hpp"
|
||||||
|
|
||||||
|
#include "terrainmaterial.hpp"
|
||||||
|
#include "terrain.hpp"
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
#include "shadows.hpp"
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
using namespace Ogre;
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& evn) :
|
||||||
|
mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend)
|
||||||
|
{
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
bool shadows = Settings::Manager::getBool("enabled", "Shadows");
|
||||||
|
mActiveProfile->setReceiveDynamicShadowsEnabled(shadows);
|
||||||
|
mActiveProfile->setReceiveDynamicShadowsDepth(shadows);
|
||||||
|
if (Settings::Manager::getBool("split", "Shadows"))
|
||||||
|
mActiveProfile->setReceiveDynamicShadowsPSSM(mRendering->getShadows()->getPSSMSetup());
|
||||||
|
else
|
||||||
|
mActiveProfile->setReceiveDynamicShadowsPSSM(0);
|
||||||
|
|
||||||
|
mActiveProfile->setShadowFar(mRendering->getShadows()->getShadowFar());
|
||||||
|
mActiveProfile->setShadowFadeStart(mRendering->getShadows()->getFadeStart());
|
||||||
|
|
||||||
|
//composite maps lead to a drastic increase 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);
|
||||||
|
terrain->setVisibilityFlags(RV_Terrain);
|
||||||
|
terrain->setRenderQueueGroup(RQG_Main);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
118
apps/openmw/mwrender/terrain.hpp
Normal file
118
apps/openmw/mwrender/terrain.hpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
#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, RenderingManager* rend, 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;
|
||||||
|
RenderingManager* mRendering;
|
||||||
|
|
||||||
|
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
|
1746
apps/openmw/mwrender/terrainmaterial.cpp
Normal file
1746
apps/openmw/mwrender/terrainmaterial.cpp
Normal file
File diff suppressed because it is too large
Load diff
271
apps/openmw/mwrender/terrainmaterial.hpp
Normal file
271
apps/openmw/mwrender/terrainmaterial.hpp
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
This source file is part of OGRE
|
||||||
|
(Object-oriented Graphics Rendering Engine)
|
||||||
|
For the latest info, see http://www.ogre3d.org/
|
||||||
|
|
||||||
|
Copyright (c) 2000-2011 Torus Knot Software Ltd
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __Ogre_TerrainMaterialGeneratorB_H__
|
||||||
|
#define __Ogre_TerrainMaterialGeneratorB_H__
|
||||||
|
|
||||||
|
#include "OgreTerrainPrerequisites.h"
|
||||||
|
#include "OgreTerrainMaterialGenerator.h"
|
||||||
|
#include "OgreGpuProgramParams.h"
|
||||||
|
|
||||||
|
namespace Ogre
|
||||||
|
{
|
||||||
|
class PSSMShadowCameraSetup;
|
||||||
|
|
||||||
|
/** \addtogroup Optional Components
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** \addtogroup Terrain
|
||||||
|
* Some details on the terrain component
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** A TerrainMaterialGenerator which can cope with normal mapped, specular mapped
|
||||||
|
terrain.
|
||||||
|
@note Requires the Cg plugin to render correctly
|
||||||
|
*/
|
||||||
|
class TerrainMaterialGeneratorB : public TerrainMaterialGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TerrainMaterialGeneratorB();
|
||||||
|
~TerrainMaterialGeneratorB();
|
||||||
|
|
||||||
|
/** Shader model 2 profile target.
|
||||||
|
*/
|
||||||
|
class SM2Profile : public TerrainMaterialGenerator::Profile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc);
|
||||||
|
~SM2Profile();
|
||||||
|
|
||||||
|
bool isVertexCompressionSupported() const {return false;}
|
||||||
|
|
||||||
|
MaterialPtr generate(const Terrain* terrain);
|
||||||
|
MaterialPtr generateForCompositeMap(const Terrain* terrain);
|
||||||
|
uint8 getMaxLayers(const Terrain* terrain) const;
|
||||||
|
void updateParams(const MaterialPtr& mat, const Terrain* terrain);
|
||||||
|
void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain);
|
||||||
|
void requestOptions(Terrain* terrain);
|
||||||
|
|
||||||
|
void setShadowFar(float far);
|
||||||
|
void setShadowFadeStart(float fadestart);
|
||||||
|
|
||||||
|
/** Whether to support normal mapping per layer in the shader (default true).
|
||||||
|
*/
|
||||||
|
bool isLayerNormalMappingEnabled() const { return mLayerNormalMappingEnabled; }
|
||||||
|
/** Whether to support normal mapping per layer in the shader (default true).
|
||||||
|
*/
|
||||||
|
void setLayerNormalMappingEnabled(bool enabled);
|
||||||
|
/** Whether to support parallax mapping per layer in the shader (default true).
|
||||||
|
*/
|
||||||
|
bool isLayerParallaxMappingEnabled() const { return mLayerParallaxMappingEnabled; }
|
||||||
|
/** Whether to support parallax mapping per layer in the shader (default true).
|
||||||
|
*/
|
||||||
|
void setLayerParallaxMappingEnabled(bool enabled);
|
||||||
|
/** Whether to support specular mapping per layer in the shader (default true).
|
||||||
|
*/
|
||||||
|
bool isLayerSpecularMappingEnabled() const { return mLayerSpecularMappingEnabled; }
|
||||||
|
/** Whether to support specular mapping per layer in the shader (default true).
|
||||||
|
*/
|
||||||
|
void setLayerSpecularMappingEnabled(bool enabled);
|
||||||
|
/** Whether to support a global colour map over the terrain in the shader,
|
||||||
|
if it's present (default true).
|
||||||
|
*/
|
||||||
|
bool isGlobalColourMapEnabled() const { return mGlobalColourMapEnabled; }
|
||||||
|
/** Whether to support a global colour map over the terrain in the shader,
|
||||||
|
if it's present (default true).
|
||||||
|
*/
|
||||||
|
void setGlobalColourMapEnabled(bool enabled);
|
||||||
|
/** Whether to support a light map over the terrain in the shader,
|
||||||
|
if it's present (default true).
|
||||||
|
*/
|
||||||
|
bool isLightmapEnabled() const { return mLightmapEnabled; }
|
||||||
|
/** Whether to support a light map over the terrain in the shader,
|
||||||
|
if it's present (default true).
|
||||||
|
*/
|
||||||
|
void setLightmapEnabled(bool enabled);
|
||||||
|
/** Whether to use the composite map to provide a lower LOD technique
|
||||||
|
in the distance (default true).
|
||||||
|
*/
|
||||||
|
bool isCompositeMapEnabled() const { return mCompositeMapEnabled; }
|
||||||
|
/** Whether to use the composite map to provide a lower LOD technique
|
||||||
|
in the distance (default true).
|
||||||
|
*/
|
||||||
|
void setCompositeMapEnabled(bool enabled);
|
||||||
|
/** Whether to support dynamic texture shadows received from other
|
||||||
|
objects, on the terrain (default true).
|
||||||
|
*/
|
||||||
|
bool getReceiveDynamicShadowsEnabled() const { return mReceiveDynamicShadows; }
|
||||||
|
/** Whether to support dynamic texture shadows received from other
|
||||||
|
objects, on the terrain (default true).
|
||||||
|
*/
|
||||||
|
void setReceiveDynamicShadowsEnabled(bool enabled);
|
||||||
|
|
||||||
|
/** Whether to use PSSM support dynamic texture shadows, and if so the
|
||||||
|
settings to use (default 0).
|
||||||
|
*/
|
||||||
|
void setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup* pssmSettings);
|
||||||
|
/** Whether to use PSSM support dynamic texture shadows, and if so the
|
||||||
|
settings to use (default 0).
|
||||||
|
*/
|
||||||
|
PSSMShadowCameraSetup* getReceiveDynamicShadowsPSSM() const { return mPSSM; }
|
||||||
|
/** Whether to use depth shadows (default false).
|
||||||
|
*/
|
||||||
|
void setReceiveDynamicShadowsDepth(bool enabled);
|
||||||
|
/** Whether to use depth shadows (default false).
|
||||||
|
*/
|
||||||
|
bool getReceiveDynamicShadowsDepth() const { return mDepthShadows; }
|
||||||
|
/** Whether to use shadows on low LOD material rendering (when using composite map) (default false).
|
||||||
|
*/
|
||||||
|
void setReceiveDynamicShadowsLowLod(bool enabled);
|
||||||
|
/** Whether to use shadows on low LOD material rendering (when using composite map) (default false).
|
||||||
|
*/
|
||||||
|
bool getReceiveDynamicShadowsLowLod() const { return mLowLodShadows; }
|
||||||
|
|
||||||
|
int getNumberOfLightsSupported() const;
|
||||||
|
|
||||||
|
/// Internal
|
||||||
|
bool _isSM3Available() const { return mSM3Available; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
enum TechniqueType
|
||||||
|
{
|
||||||
|
HIGH_LOD,
|
||||||
|
LOW_LOD,
|
||||||
|
RENDER_COMPOSITE_MAP
|
||||||
|
};
|
||||||
|
void addTechnique(const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt);
|
||||||
|
|
||||||
|
/// Interface definition for helper class to generate shaders
|
||||||
|
class ShaderHelper : public TerrainAlloc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderHelper() {}
|
||||||
|
virtual ~ShaderHelper() {}
|
||||||
|
virtual HighLevelGpuProgramPtr generateVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
virtual HighLevelGpuProgramPtr generateFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
virtual void updateParams(const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap);
|
||||||
|
protected:
|
||||||
|
virtual String getVertexProgramName(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
virtual String getFragmentProgramName(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
virtual HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) = 0;
|
||||||
|
virtual HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) = 0;
|
||||||
|
virtual void generateVertexProgramSource(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
virtual void generateFragmentProgramSource(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
virtual void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0;
|
||||||
|
virtual void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0;
|
||||||
|
virtual void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) = 0;
|
||||||
|
virtual void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) = 0;
|
||||||
|
virtual void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0;
|
||||||
|
virtual void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0;
|
||||||
|
virtual void defaultVpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog);
|
||||||
|
virtual void defaultFpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog);
|
||||||
|
virtual void updateVpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params);
|
||||||
|
virtual void updateFpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params);
|
||||||
|
static String getChannel(uint idx);
|
||||||
|
|
||||||
|
size_t mShadowSamplerStartHi;
|
||||||
|
size_t mShadowSamplerStartLo;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Utility class to help with generating shaders for Cg / HLSL.
|
||||||
|
class ShaderHelperCg : public ShaderHelper
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
uint generateVpDynamicShadowsParams(uint texCoordStart, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateVpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateFpDynamicShadowsHelpers(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateFpDynamicShadowsParams(uint* texCoord, uint* sampler, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
void generateFpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderHelperHLSL : public ShaderHelperCg
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Utility class to help with generating shaders for GLSL.
|
||||||
|
class ShaderHelperGLSL : public ShaderHelper
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||||
|
void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {}
|
||||||
|
void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {}
|
||||||
|
void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) {}
|
||||||
|
void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) {}
|
||||||
|
void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {}
|
||||||
|
void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderHelper* mShaderGen;
|
||||||
|
bool mLayerNormalMappingEnabled;
|
||||||
|
bool mLayerParallaxMappingEnabled;
|
||||||
|
bool mLayerSpecularMappingEnabled;
|
||||||
|
bool mGlobalColourMapEnabled;
|
||||||
|
bool mLightmapEnabled;
|
||||||
|
bool mCompositeMapEnabled;
|
||||||
|
bool mReceiveDynamicShadows;
|
||||||
|
PSSMShadowCameraSetup* mPSSM;
|
||||||
|
bool mDepthShadows;
|
||||||
|
bool mLowLodShadows;
|
||||||
|
bool mSM3Available;
|
||||||
|
float mShadowFar;
|
||||||
|
float mShadowFadeStart;
|
||||||
|
|
||||||
|
bool isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
293
apps/openmw/mwrender/water.cpp
Normal file
293
apps/openmw/mwrender/water.cpp
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
#include "water.hpp"
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include "sky.hpp"
|
||||||
|
#include "renderingmanager.hpp"
|
||||||
|
|
||||||
|
using namespace Ogre;
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
|
||||||
|
Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
|
||||||
|
mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()),
|
||||||
|
mIsUnderwater(false), mVisibilityFlags(0),
|
||||||
|
mReflectionTarget(0), mActive(1), mToggled(1)
|
||||||
|
{
|
||||||
|
mSky = sky;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false);
|
||||||
|
} catch(...) {}
|
||||||
|
|
||||||
|
mTop = cell->water;
|
||||||
|
|
||||||
|
mIsUnderwater = false;
|
||||||
|
|
||||||
|
mWaterPlane = Plane(Vector3::UNIT_Y, 0);
|
||||||
|
|
||||||
|
MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z);
|
||||||
|
|
||||||
|
mWater = mSceneManager->createEntity("water");
|
||||||
|
mWater->setVisibilityFlags(RV_Water);
|
||||||
|
mWater->setRenderQueueGroup(RQG_Water);
|
||||||
|
mWater->setCastShadows(false);
|
||||||
|
|
||||||
|
mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water")
|
||||||
|
+ RV_Statics * Settings::Manager::getBool("reflect statics", "Water")
|
||||||
|
+ RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water")
|
||||||
|
+ RV_Actors * Settings::Manager::getBool("reflect actors", "Water")
|
||||||
|
+ RV_Misc * Settings::Manager::getBool("reflect misc", "Water")
|
||||||
|
+ RV_Sky;
|
||||||
|
|
||||||
|
mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode();
|
||||||
|
mWaterNode->setPosition(0, mTop, 0);
|
||||||
|
|
||||||
|
mReflectionCamera = mSceneManager->createCamera("ReflectionCamera");
|
||||||
|
|
||||||
|
if(!(cell->data.flags & cell->Interior))
|
||||||
|
{
|
||||||
|
mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY));
|
||||||
|
}
|
||||||
|
mWaterNode->attachObject(mWater);
|
||||||
|
|
||||||
|
// Create rendertarget for reflection
|
||||||
|
int rttsize = Settings::Manager::getInt("rtt size", "Water");
|
||||||
|
|
||||||
|
TexturePtr tex;
|
||||||
|
if (Settings::Manager::getBool("shader", "Water"))
|
||||||
|
{
|
||||||
|
tex = TextureManager::getSingleton().createManual("WaterReflection",
|
||||||
|
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET);
|
||||||
|
|
||||||
|
RenderTarget* rtt = tex->getBuffer()->getRenderTarget();
|
||||||
|
Viewport* vp = rtt->addViewport(mReflectionCamera);
|
||||||
|
vp->setOverlaysEnabled(false);
|
||||||
|
vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f));
|
||||||
|
vp->setShadowsEnabled(false);
|
||||||
|
vp->setVisibilityMask( mVisibilityFlags );
|
||||||
|
// use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain)
|
||||||
|
//vp->setMaterialScheme("Fallback");
|
||||||
|
rtt->addListener(this);
|
||||||
|
rtt->setActive(true);
|
||||||
|
|
||||||
|
mReflectionTarget = rtt;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCompositorName = RenderingManager::useMRT() ? "Underwater" : "UnderwaterNoMRT";
|
||||||
|
|
||||||
|
createMaterial();
|
||||||
|
mWater->setMaterial(mMaterial);
|
||||||
|
|
||||||
|
mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water");
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------
|
||||||
|
// ---------------------------------- reflection debug overlay ----------------------------------
|
||||||
|
// ----------------------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
if (Settings::Manager::getBool("shader", "Water"))
|
||||||
|
{
|
||||||
|
OverlayManager& mgr = OverlayManager::getSingleton();
|
||||||
|
Overlay* overlay;
|
||||||
|
// destroy if already exists
|
||||||
|
if (overlay = mgr.getByName("ReflectionDebugOverlay"))
|
||||||
|
mgr.destroy(overlay);
|
||||||
|
|
||||||
|
overlay = mgr.create("ReflectionDebugOverlay");
|
||||||
|
|
||||||
|
if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture"))
|
||||||
|
MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture");
|
||||||
|
MaterialPtr debugMat = MaterialManager::getSingleton().create(
|
||||||
|
"Ogre/ReflectionDebugTexture",
|
||||||
|
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||||
|
|
||||||
|
debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
|
||||||
|
TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName());
|
||||||
|
t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
|
||||||
|
|
||||||
|
OverlayContainer* debugPanel;
|
||||||
|
|
||||||
|
// destroy container if exists
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (debugPanel =
|
||||||
|
static_cast<OverlayContainer*>(
|
||||||
|
mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel"
|
||||||
|
)))
|
||||||
|
mgr.destroyOverlayElement(debugPanel);
|
||||||
|
}
|
||||||
|
catch (Ogre::Exception&) {}
|
||||||
|
|
||||||
|
debugPanel = (OverlayContainer*)
|
||||||
|
(OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel"));
|
||||||
|
debugPanel->_setPosition(0, 0.55);
|
||||||
|
debugPanel->_setDimensions(0.3, 0.3);
|
||||||
|
debugPanel->setMaterialName(debugMat->getName());
|
||||||
|
debugPanel->show();
|
||||||
|
overlay->add2D(debugPanel);
|
||||||
|
overlay->show();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::setActive(bool active)
|
||||||
|
{
|
||||||
|
mActive = active;
|
||||||
|
updateVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
Water::~Water()
|
||||||
|
{
|
||||||
|
MeshManager::getSingleton().remove("water");
|
||||||
|
|
||||||
|
mWaterNode->detachObject(mWater);
|
||||||
|
mSceneManager->destroyEntity(mWater);
|
||||||
|
mSceneManager->destroySceneNode(mWaterNode);
|
||||||
|
|
||||||
|
CompositorManager::getSingleton().removeCompositorChain(mViewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::changeCell(const ESM::Cell* cell)
|
||||||
|
{
|
||||||
|
mTop = cell->water;
|
||||||
|
|
||||||
|
if(!(cell->data.flags & cell->Interior))
|
||||||
|
mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY));
|
||||||
|
else
|
||||||
|
setHeight(mTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::setHeight(const float height)
|
||||||
|
{
|
||||||
|
mTop = height;
|
||||||
|
mWaterNode->setPosition(0, height, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::toggle()
|
||||||
|
{
|
||||||
|
mToggled = !mToggled;
|
||||||
|
updateVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::checkUnderwater(float y)
|
||||||
|
{
|
||||||
|
if (!mActive) return;
|
||||||
|
if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID)
|
||||||
|
{
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false);
|
||||||
|
|
||||||
|
// tell the shader we are not underwater
|
||||||
|
Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0);
|
||||||
|
if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false))
|
||||||
|
pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(0));
|
||||||
|
|
||||||
|
mWater->setRenderQueueGroup(RQG_Water);
|
||||||
|
|
||||||
|
mIsUnderwater = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID)
|
||||||
|
{
|
||||||
|
if (mUnderwaterEffect)
|
||||||
|
CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, true);
|
||||||
|
|
||||||
|
// tell the shader we are underwater
|
||||||
|
Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0);
|
||||||
|
if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false))
|
||||||
|
pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(1));
|
||||||
|
|
||||||
|
mWater->setRenderQueueGroup(RQG_UnderWater);
|
||||||
|
|
||||||
|
mIsUnderwater = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY)
|
||||||
|
{
|
||||||
|
return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
|
||||||
|
{
|
||||||
|
if (evt.source == mReflectionTarget)
|
||||||
|
{
|
||||||
|
mReflectionCamera->setOrientation(mCamera->getDerivedOrientation());
|
||||||
|
mReflectionCamera->setPosition(mCamera->getDerivedPosition());
|
||||||
|
mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance());
|
||||||
|
mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance());
|
||||||
|
mReflectionCamera->setAspectRatio(mCamera->getAspectRatio());
|
||||||
|
mReflectionCamera->setFOVy(mCamera->getFOVy());
|
||||||
|
|
||||||
|
// Some messy code to get the skybox to show up at all
|
||||||
|
// The problem here is that it gets clipped by the water plane
|
||||||
|
// Therefore scale it up a bit
|
||||||
|
Vector3 pos = mCamera->getRealPosition();
|
||||||
|
pos.y = mTop*2 - pos.y;
|
||||||
|
mSky->setSkyPosition(pos);
|
||||||
|
mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f);
|
||||||
|
|
||||||
|
mReflectionCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop));
|
||||||
|
mReflectionCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::postRenderTargetUpdate(const RenderTargetEvent& evt)
|
||||||
|
{
|
||||||
|
if (evt.source == mReflectionTarget)
|
||||||
|
{
|
||||||
|
mSky->resetSkyPosition();
|
||||||
|
mSky->scaleSky(1);
|
||||||
|
mReflectionCamera->disableCustomNearClipPlane();
|
||||||
|
mReflectionCamera->disableReflection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::createMaterial()
|
||||||
|
{
|
||||||
|
mMaterial = MaterialManager::getSingleton().getByName("Water");
|
||||||
|
|
||||||
|
// these have to be set in code
|
||||||
|
std::string textureNames[32];
|
||||||
|
for (int i=0; i<32; ++i)
|
||||||
|
{
|
||||||
|
textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds";
|
||||||
|
}
|
||||||
|
mMaterial->getTechnique(1)->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2);
|
||||||
|
|
||||||
|
// use technique without shaders if reflection is disabled
|
||||||
|
if (mReflectionTarget == 0)
|
||||||
|
mMaterial->removeTechnique(0);
|
||||||
|
|
||||||
|
if (Settings::Manager::getBool("shader", "Water"))
|
||||||
|
{
|
||||||
|
CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mViewport)->getCompositor("gbuffer");
|
||||||
|
|
||||||
|
TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0);
|
||||||
|
TextureUnitState* tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("refractionMap");
|
||||||
|
if (tus != 0)
|
||||||
|
tus->setTexture(colorTexture);
|
||||||
|
|
||||||
|
TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1);
|
||||||
|
tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("depthMap");
|
||||||
|
if (tus != 0)
|
||||||
|
tus->setTexture(depthTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::setViewportBackground(const ColourValue& bg)
|
||||||
|
{
|
||||||
|
if (mReflectionTarget)
|
||||||
|
mReflectionTarget->getViewport(0)->setBackgroundColour(bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::updateVisible()
|
||||||
|
{
|
||||||
|
mWater->setVisible(mToggled && mActive);
|
||||||
|
if (mReflectionTarget)
|
||||||
|
mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
69
apps/openmw/mwrender/water.hpp
Normal file
69
apps/openmw/mwrender/water.hpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef GAME_MWRENDER_WATER_H
|
||||||
|
#define GAME_MWRENDER_WATER_H
|
||||||
|
|
||||||
|
#include <Ogre.h>
|
||||||
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
|
||||||
|
namespace MWRender {
|
||||||
|
|
||||||
|
class SkyManager;
|
||||||
|
|
||||||
|
/// Water rendering
|
||||||
|
class Water : public Ogre::RenderTargetListener
|
||||||
|
{
|
||||||
|
static const int CELL_SIZE = 8192;
|
||||||
|
Ogre::Camera *mCamera;
|
||||||
|
Ogre::SceneManager *mSceneManager;
|
||||||
|
Ogre::Viewport *mViewport;
|
||||||
|
|
||||||
|
Ogre::Plane mWaterPlane;
|
||||||
|
Ogre::SceneNode *mWaterNode;
|
||||||
|
Ogre::Entity *mWater;
|
||||||
|
|
||||||
|
bool mIsUnderwater;
|
||||||
|
bool mActive;
|
||||||
|
bool mToggled;
|
||||||
|
int mTop;
|
||||||
|
|
||||||
|
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
|
||||||
|
void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
|
||||||
|
void updateVisible();
|
||||||
|
|
||||||
|
SkyManager* mSky;
|
||||||
|
|
||||||
|
std::string mCompositorName;
|
||||||
|
|
||||||
|
void createMaterial();
|
||||||
|
Ogre::MaterialPtr mMaterial;
|
||||||
|
|
||||||
|
Ogre::Camera* mReflectionCamera;
|
||||||
|
|
||||||
|
Ogre::RenderTarget* mReflectionTarget;
|
||||||
|
|
||||||
|
bool mUnderwaterEffect;
|
||||||
|
int mVisibilityFlags;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell);
|
||||||
|
~Water();
|
||||||
|
|
||||||
|
void setActive(bool active);
|
||||||
|
|
||||||
|
void toggle();
|
||||||
|
|
||||||
|
void setViewportBackground(const Ogre::ColourValue& bg);
|
||||||
|
|
||||||
|
void checkUnderwater(float y);
|
||||||
|
void changeCell(const ESM::Cell* cell);
|
||||||
|
void setHeight(const float height);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -133,11 +133,70 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OpGetWaterLevel : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context
|
||||||
|
= static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell();
|
||||||
|
runtime.push (cell->mWaterLevel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpSetWaterLevel : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context
|
||||||
|
= static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
Interpreter::Type_Float level = runtime[0].mFloat;
|
||||||
|
|
||||||
|
MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell();
|
||||||
|
|
||||||
|
if (!(cell->cell->data.flags & ESM::Cell::Interior))
|
||||||
|
throw std::runtime_error("Can't set water level in exterior cell");
|
||||||
|
|
||||||
|
cell->mWaterLevel = level;
|
||||||
|
context.getEnvironment().mWorld->setWaterHeight(cell->mWaterLevel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpModWaterLevel : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context
|
||||||
|
= static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
Interpreter::Type_Float level = runtime[0].mFloat;
|
||||||
|
|
||||||
|
MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell();
|
||||||
|
|
||||||
|
if (!(cell->cell->data.flags & ESM::Cell::Interior))
|
||||||
|
throw std::runtime_error("Can't set water level in exterior cell");
|
||||||
|
|
||||||
|
cell->mWaterLevel +=level;
|
||||||
|
context.getEnvironment().mWorld->setWaterHeight(cell->mWaterLevel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const int opcodeCellChanged = 0x2000000;
|
const int opcodeCellChanged = 0x2000000;
|
||||||
const int opcodeCOC = 0x2000026;
|
const int opcodeCOC = 0x2000026;
|
||||||
const int opcodeCOE = 0x200008e;
|
const int opcodeCOE = 0x200008e;
|
||||||
const int opcodeGetInterior = 0x2000131;
|
const int opcodeGetInterior = 0x2000131;
|
||||||
const int opcodeGetPCCell = 0x2000136;
|
const int opcodeGetPCCell = 0x2000136;
|
||||||
|
const int opcodeGetWaterLevel = 0x2000141;
|
||||||
|
const int opcodeSetWaterLevel = 0x2000142;
|
||||||
|
const int opcodeModWaterLevel = 0x2000143;
|
||||||
|
|
||||||
void registerExtensions (Compiler::Extensions& extensions)
|
void registerExtensions (Compiler::Extensions& extensions)
|
||||||
{
|
{
|
||||||
|
@ -146,8 +205,11 @@ namespace MWScript
|
||||||
extensions.registerInstruction ("centeroncell", "S", opcodeCOC);
|
extensions.registerInstruction ("centeroncell", "S", opcodeCOC);
|
||||||
extensions.registerInstruction ("coe", "ll", opcodeCOE);
|
extensions.registerInstruction ("coe", "ll", opcodeCOE);
|
||||||
extensions.registerInstruction ("centeronexterior", "ll", opcodeCOE);
|
extensions.registerInstruction ("centeronexterior", "ll", opcodeCOE);
|
||||||
|
extensions.registerInstruction ("setwaterlevel", "f", opcodeSetWaterLevel);
|
||||||
|
extensions.registerInstruction ("modwaterlevel", "f", opcodeModWaterLevel);
|
||||||
extensions.registerFunction ("getinterior", 'l', "", opcodeGetInterior);
|
extensions.registerFunction ("getinterior", 'l', "", opcodeGetInterior);
|
||||||
extensions.registerFunction ("getpccell", 'l', "c", opcodeGetPCCell);
|
extensions.registerFunction ("getpccell", 'l', "c", opcodeGetPCCell);
|
||||||
|
extensions.registerFunction ("getwaterlevel", 'f', "", opcodeGetWaterLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
|
@ -157,6 +219,9 @@ namespace MWScript
|
||||||
interpreter.installSegment5 (opcodeCOE, new OpCOE);
|
interpreter.installSegment5 (opcodeCOE, new OpCOE);
|
||||||
interpreter.installSegment5 (opcodeGetInterior, new OpGetInterior);
|
interpreter.installSegment5 (opcodeGetInterior, new OpGetInterior);
|
||||||
interpreter.installSegment5 (opcodeGetPCCell, new OpGetPCCell);
|
interpreter.installSegment5 (opcodeGetPCCell, new OpGetPCCell);
|
||||||
|
interpreter.installSegment5 (opcodeGetWaterLevel, new OpGetWaterLevel);
|
||||||
|
interpreter.installSegment5 (opcodeSetWaterLevel, new OpSetWaterLevel);
|
||||||
|
interpreter.installSegment5 (opcodeModWaterLevel, new OpModWaterLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue