Merge remote-tracking branch 'scrawl/osg' into appveyor-osg

coverity_scan
Alexander "Ace" Olofsson 10 years ago
commit c40f59179f

@ -5,6 +5,7 @@ language: cpp
branches:
only:
- master
- osg
- coverity_scan
- /openmw-.*$/
env:
@ -48,9 +49,9 @@ notifications:
email:
on_success: change
on_failure: always
irc:
channels:
- "chat.freenode.net#openmw"
on_success: change
on_failure: always
use_notice: true
#irc:
# channels:
# - "chat.freenode.net#openmw"
# on_success: change
# on_failure: always
# use_notice: true

@ -12,9 +12,10 @@ echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
sudo apt-get update -qq
sudo apt-get install -qq libgtest-dev google-mock
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04
if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi
sudo mkdir /usr/src/gtest/build
cd /usr/src/gtest/build

@ -54,15 +54,13 @@ endif (ANDROID)
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_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(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)")
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
# Apps and tools
option(BUILD_OPENMW "build OpenMW" ON)
option(BUILD_BSATOOL "build BSA extractor" ON)
option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON)
@ -72,7 +70,6 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON)
option(BUILD_WIZARD "build Installation Wizard" ON)
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
option(BUILD_NIFTEST "build nif file tester" OFF)
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
# OS X deployment
@ -136,17 +133,11 @@ endif()
if (WIN32)
if(NOT MINGW)
set(Boost_USE_STATIC_LIBS ON)
set(PLATFORM_INCLUDE_DIR "platform")
add_definitions(-DBOOST_ALL_NO_LIB)
endif(NOT MINGW)
# Suppress WinMain(), provided by SDL
add_definitions(-DSDL_MAIN_HANDLED)
else (WIN32)
set(PLATFORM_INCLUDE_DIR "")
endif (WIN32)
if (MSVC10)
set(PLATFORM_INCLUDE_DIR "")
endif()
# Dependencies
@ -180,10 +171,8 @@ IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON)
endif()
find_package(OGRE REQUIRED)
if (${OGRE_VERSION} VERSION_LESS "1.9")
message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org")
endif()
find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
find_package(MyGUI REQUIRED)
if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
@ -195,87 +184,22 @@ find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED)
set(OGRE_PLUGIN_INCLUDE_DIRS "")
set(OGRE_STATIC_PLUGINS "")
macro(add_static_ogre_plugin PLUGIN)
if(OGRE_${PLUGIN}_FOUND)
# strip RenderSystem_ or Plugin_ prefix from plugin name
string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN})
string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP})
add_definitions(-DENABLE_PLUGIN_${PLUGIN_NAME})
list(APPEND OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIRS})
list(APPEND OGRE_STATIC_PLUGINS ${OGRE_${PLUGIN}_LIBRARIES})
endif(OGRE_${PLUGIN}_FOUND)
endmacro(add_static_ogre_plugin)
if(OGRE_STATIC)
# set up OGRE_PLUGIN_INCLUDE_DIRS and OGRE_STATIC_PLUGINS
add_static_ogre_plugin(Plugin_OctreeSceneManager)
add_static_ogre_plugin(Plugin_ParticleFX)
find_package(Cg)
if(Cg_FOUND)
add_static_ogre_plugin(Plugin_CgProgramManager)
list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES})
endif(Cg_FOUND)
if (ANDROID)
add_static_ogre_plugin(RenderSystem_GLES2)
else ()
add_static_ogre_plugin(RenderSystem_GL)
endif ()
if(WIN32)
add_static_ogre_plugin(RenderSystem_Direct3D9)
endif(WIN32)
endif(OGRE_STATIC)
include_directories("." ${LIBS_DIR}
include_directories("."
SYSTEM
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS}
${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR}
${SDL2_INCLUDE_DIR}
${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR}
${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${BULLET_INCLUDE_DIRS}
)
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${MYGUI_LIB_DIR})
if(MYGUI_STATIC)
add_definitions(-DMYGUI_STATIC)
endif (MYGUI_STATIC)
if (APPLE)
# List used Ogre plugins
SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL}
${OGRE_Plugin_ParticleFX_LIBRARY_REL})
# Actually we must use OGRE_Plugin_CgProgramManager_FOUND but it's
# not reliable and equals TRUE even if there's no Ogre Cg plugin
if (Cg_FOUND)
set(USED_OGRE_PLUGINS ${USED_OGRE_PLUGINS}
${OGRE_Plugin_CgProgramManager_LIBRARY_REL})
endif ()
if (${OGRE_PLUGIN_DIR_REL}})
set(OGRE_PLUGINS_REL_FOUND TRUE)
endif ()
if (${OGRE_PLUGIN_DIR_DBG})
set(OGRE_PLUGINS_DBG_FOUND TRUE)
endif ()
if (${OGRE_PLUGINS_REL_FOUND})
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
else ()
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
endif ()
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
"${APP_BUNDLE_DIR}/Contents/Info.plist")
@ -286,30 +210,7 @@ endif (APPLE)
# Set up DEBUG define
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
# Set up Ogre plugin folder & debug suffix
if (APPLE)
# Ogre on OS X doesn't use "_d" suffix (see Ogre's CMakeLists.txt)
add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="")
else ()
add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d")
endif()
if (APPLE AND OPENMW_OSX_DEPLOYMENT)
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
add_definitions(-DOGRE_PLUGIN_DIR="")
else()
if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "")
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
else()
set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR})
endif()
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
endif()
add_subdirectory(files/)
add_subdirectory(files/mygui)
# Specify build paths
@ -326,9 +227,6 @@ endif (APPLE)
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
"${OpenMW_BINARY_DIR}/openmw.cfg")
@ -394,7 +292,9 @@ IF(NOT WIN32 AND NOT APPLE)
SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir")
# Install binaries
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
IF(BUILD_OPENMW)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENMW)
IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" )
ENDIF(BUILD_LAUNCHER)
@ -413,19 +313,15 @@ IF(NOT WIN32 AND NOT APPLE)
IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENCS)
IF(BUILD_NIFTEST)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
ENDIF(BUILD_NIFTEST)
IF(BUILD_WIZARD)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" )
ENDIF(BUILD_WIZARD)
if(BUILD_MYGUI_PLUGIN)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
ENDIF(BUILD_MYGUI_PLUGIN)
#if(BUILD_MYGUI_PLUGIN)
# INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
#ENDIF(BUILD_MYGUI_PLUGIN)
# Install licenses
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
# Install icon and desktop file
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw")
@ -437,7 +333,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install global configuration files
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
@ -460,7 +355,6 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
DESTINATION ".")
@ -546,31 +440,22 @@ if(WIN32)
include(CPack)
endif(WIN32)
# Libs
include_directories(libs)
add_subdirectory(libs/openengine)
# Extern
add_subdirectory (extern/shiny)
add_subdirectory (extern/ogre-ffmpeg-videoplayer)
add_subdirectory (extern/osg-ffmpeg-videoplayer)
add_subdirectory (extern/oics)
add_subdirectory (extern/sdl4ogre)
# Components
add_subdirectory (components)
# Plugins
if (BUILD_MYGUI_PLUGIN)
add_subdirectory(plugins/mygui_resource_plugin)
endif()
#Testing
if (BUILD_NIFTEST)
add_subdirectory(components/nif/tests/)
endif(BUILD_NIFTEST)
#if (BUILD_MYGUI_PLUGIN)
# add_subdirectory(plugins/mygui_resource_plugin)
#endif()
# Apps and tools
add_subdirectory( apps/openmw )
if (BUILD_OPENMW)
add_subdirectory( apps/openmw )
endif()
if (BUILD_BSATOOL)
add_subdirectory( apps/bsatool )
@ -652,12 +537,6 @@ if (WIN32)
4987 # nonstandard extension used (triggered by setjmp.h)
4996 # Function was declared deprecated
# cause by ogre extensivly
4193 # #pragma warning(pop) : no matching '#pragma warning(push)'
4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY'
4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY'
4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h)
# caused by boost
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
@ -685,10 +564,6 @@ if (WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}")
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
set(SHINY_WARNINGS "${WARNINGS} /wd4245")
set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}")
# oics uses tinyxml, which has an initialized but unused variable
set(OICS_WARNINGS "${WARNINGS} /wd4189")
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}")
@ -714,7 +589,6 @@ if (APPLE)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
@ -728,90 +602,14 @@ if (APPLE)
set(OPENCS_BUNDLE_NAME "OpenMW-CS.app")
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
set(ABSOLUTE_PLUGINS "")
foreach (PLUGIN ${USED_OGRE_PLUGINS})
get_filename_component(PLUGIN_ABS ${PLUGIN} REALPATH)
set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS})
endforeach ()
install(CODE "
set(BU_CHMOD_BUNDLE_ITEMS ON)
include(BundleUtilities)
" COMPONENT Runtime)
# installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX})
# and returns list of install paths for all installed plugins
function (install_plugins_for_bundle bundle_path plugins_var)
set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Frameworks")
set(PLUGINS "")
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}")
foreach (PLUGIN ${ABSOLUTE_PLUGINS})
get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME)
get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE)
set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}")
set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}")
install(CODE "
copy_resolved_framework_into_bundle(\"${PLUGIN}/${PLUGIN_RELATIVE_WE}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\")
" COMPONENT Runtime)
endforeach ()
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
endfunction (install_plugins_for_bundle)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
#For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail
set(DIRS "")
# Overriding item resolving during installation, it needed if
# some library already has been "fixed up", i.e. its id name contains @executable_path,
# but library is not embedded in bundle. For example, it's Ogre.framework from Ogre SDK.
# Current implementation of GetPrerequsities/BundleUtilities doesn't handle that case.
#
# Current limitations:
# 1. Handles only frameworks, not simple libs
INSTALL(CODE "
cmake_policy(SET CMP0009 OLD)
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH})
set(OPENMW_RESOLVED_ITEMS \"\")
function(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var)
if(item MATCHES \"@executable_path\" AND NOT \${\${resolved_var}})
if (item MATCHES \"Frameworks\") # if it is a framework
# get last segment of path
get_filename_component(fname \"\${item}\" NAME_WE)
find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} \${CMAKE_SYSTEM_FRAMEWORK_PATH})
if (ri)
string(REGEX REPLACE \"^.*/Frameworks/.*\\\\.framework\" \"\" item_part \${item})
set(ri \"\${ri}\${item_part}\")
set(\${resolved_item_var} \${ri} PARENT_SCOPE)
set(\${resolved_var} 1 PARENT_SCOPE)
endif()
else()
# code path for standard (non-framework) libs (ogre & qt pugins)
get_filename_component(fname \"\${item}\" NAME_WE)
string(REGEX REPLACE \"^lib\" \"\" fname \${fname})
find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /usr/lib /usr/local/lib)
if (ri)
set(\${resolved_item_var} \${ri} PARENT_SCOPE)
set(\${resolved_var} 1 PARENT_SCOPE)
endif ()
endif()
endif()
endfunction(gp_resolve_item_override)
fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\")
fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\")
" COMPONENT Runtime)
include(CPack)
endif (APPLE)

@ -1,4 +1,5 @@
#include <iostream>
#include <iomanip>
#include <vector>
#include <exception>
@ -237,12 +238,14 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
}
// Get a stream for the file to extract
Ogre::DataStreamPtr data = bsa.getFile(archivePath.c_str());
Files::IStreamPtr stream = bsa.getFile(archivePath.c_str());
bfs::ofstream out(target, std::ios::binary);
// Write the file to disk
std::cout << "Extracting " << info.extractfile << " to " << target << std::endl;
out.write(data->getAsString().c_str(), data->size());
out << stream->rdbuf();
out.close();
return 0;
@ -276,12 +279,12 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info)
// Get a stream for the file to extract
// (inefficient because getFile iter on the list again)
Ogre::DataStreamPtr data = bsa.getFile(archivePath);
Files::IStreamPtr data = bsa.getFile(archivePath);
bfs::ofstream out(target, std::ios::binary);
// Write the file to disk
std::cout << "Extracting " << target << std::endl;
out.write(data->getAsString().c_str(), data->size());
out << data->rdbuf();
out.close();
}

@ -4,6 +4,7 @@
#include <list>
#include <map>
#include <set>
#include <fstream>
#include <boost/program_options.hpp>
@ -284,7 +285,7 @@ void printRaw(ESM::ESMReader &esm)
esm.getRecHeader();
while(esm.hasMoreSubs())
{
uint64_t offs = esm.getOffset();
size_t offs = esm.getFileOffset();
esm.getSubName();
esm.skipHSub();
n = esm.retSubName();

@ -2,8 +2,7 @@
#include <stdexcept>
#include <OgreImage.h>
#include <OgreColourValue.h>
#include <osgDB/WriteFile>
#include <components/esm/creaturestate.hpp>
#include <components/esm/containerstate.hpp>
@ -15,12 +14,14 @@
namespace
{
void convertImage(char* data, int size, int width, int height, Ogre::PixelFormat pf, const std::string& out)
void convertImage(char* data, int size, int width, int height, GLenum pf, const std::string& out)
{
Ogre::Image screenshot;
Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(data, size));
screenshot.loadRawData(stream, width, height, 1, pf);
screenshot.save(out);
osg::ref_ptr<osg::Image> image (new osg::Image);
image->allocateImage(width, height, 1, pf, GL_UNSIGNED_BYTE);
memcpy(image->data(), data, size);
image->flipVertical();
osgDB::writeImageFile(*image, out);
}
@ -71,17 +72,20 @@ namespace ESSImport
data.resize(esm.getSubSize());
esm.getExact(&data[0], data.size());
Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(&data[0], data.size()));
mGlobalMapImage.loadRawData(stream, maph.size, maph.size, 1, Ogre::PF_BYTE_RGB);
mGlobalMapImage = new osg::Image;
mGlobalMapImage->allocateImage(maph.size, maph.size, 1, GL_RGB, GL_UNSIGNED_BYTE);
memcpy(mGlobalMapImage->data(), &data[0], data.size());
// to match openmw size
mGlobalMapImage.resize(maph.size*2, maph.size*2, Ogre::Image::FILTER_BILINEAR);
// FIXME: filtering?
mGlobalMapImage->scaleImage(maph.size*2, maph.size*2, 1, GL_UNSIGNED_BYTE);
}
void ConvertFMAP::write(ESM::ESMWriter &esm)
{
int numcells = mGlobalMapImage.getWidth() / 18; // NB truncating, doesn't divide perfectly
int numcells = mGlobalMapImage->s() / 18; // NB truncating, doesn't divide perfectly
// with the 512x512 map the game has by default
int cellSize = mGlobalMapImage.getWidth()/numcells;
int cellSize = mGlobalMapImage->s()/numcells;
// Note the upper left corner of the (0,0) cell should be at (width/2, height/2)
@ -90,12 +94,14 @@ namespace ESSImport
mContext->mGlobalMapState.mBounds.mMinY = -(numcells-1)/2;
mContext->mGlobalMapState.mBounds.mMaxY = numcells/2;
Ogre::Image image2;
std::vector<Ogre::uint8> data;
osg::ref_ptr<osg::Image> image2 (new osg::Image);
int width = cellSize*numcells;
int height = cellSize*numcells;
std::vector<unsigned char> data;
data.resize(width*height*4, 0);
image2.loadDynamicImage(&data[0], width, height, Ogre::PF_BYTE_RGBA);
image2->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
memcpy(image2->data(), &data[0], data.size());
for (std::set<std::pair<int, int> >::const_iterator it = mContext->mExploredCells.begin(); it != mContext->mExploredCells.end(); ++it)
{
@ -108,8 +114,8 @@ namespace ESSImport
continue;
}
int imageLeftSrc = mGlobalMapImage.getWidth()/2;
int imageTopSrc = mGlobalMapImage.getHeight()/2;
int imageLeftSrc = mGlobalMapImage->s()/2;
int imageTopSrc = mGlobalMapImage->t()/2;
imageLeftSrc += it->first * cellSize;
imageTopSrc -= it->second * cellSize;
int imageLeftDst = width/2;
@ -118,13 +124,31 @@ namespace ESSImport
imageTopDst -= it->second * cellSize;
for (int x=0; x<cellSize; ++x)
for (int y=0; y<cellSize; ++y)
image2.setColourAt(mGlobalMapImage.getColourAt(imageLeftSrc+x, imageTopSrc+y, 0)
, imageLeftDst+x, imageTopDst+y, 0);
{
unsigned int col = *(unsigned int*)mGlobalMapImage->data(imageLeftSrc+x, imageTopSrc+y, 0);
*(unsigned int*)image2->data(imageLeftDst+x, imageTopDst+y, 0) = col;
}
}
std::stringstream ostream;
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!readerwriter)
{
std::cerr << "can't write global map image, no png readerwriter found" << std::endl;
return;
}
image2->flipVertical();
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image2, ostream);
if (!result.success())
{
std::cerr << "can't write global map image: " << result.message() << std::endl;
return;
}
Ogre::DataStreamPtr encoded = image2.encode("png");
mContext->mGlobalMapState.mImageData.resize(encoded->size());
encoded->read(&mContext->mGlobalMapState.mImageData[0], encoded->size());
std::string outData = ostream.str();
mContext->mGlobalMapState.mImageData = std::vector<char>(outData.begin(), outData.end());
esm.startRecord(ESM::REC_GMAP);
mContext->mGlobalMapState.save(esm);
@ -194,7 +218,7 @@ namespace ESSImport
std::ostringstream filename;
filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga";
convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str());
convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, GL_RGBA, filename.str());
}
}

@ -1,7 +1,10 @@
#ifndef OPENMW_ESSIMPORT_CONVERTER_H
#define OPENMW_ESSIMPORT_CONVERTER_H
#include <OgreImage.h>
#include <limits>
#include <osg/Image>
#include <osg/ref_ptr>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
@ -311,7 +314,7 @@ public:
virtual void write(ESM::ESMWriter &esm);
private:
Ogre::Image mGlobalMapImage;
osg::ref_ptr<osg::Image> mGlobalMapImage;
};
class ConvertCell : public Converter

@ -1,7 +1,11 @@
#include "importer.hpp"
#include <iomanip>
#include <boost/shared_ptr.hpp>
#include <OgreRoot.h>
#include <osgDB/ReadFile>
#include <osg/ImageUtils>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
@ -32,13 +36,48 @@ namespace
void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out)
{
Ogre::Image screenshot;
std::vector<unsigned char> screenshotData = fileHeader.mSCRS; // MemoryDataStream doesn't work with const data :(
Ogre::DataStreamPtr screenshotStream (new Ogre::MemoryDataStream(&screenshotData[0], screenshotData.size()));
screenshot.loadRawData(screenshotStream, 128, 128, 1, Ogre::PF_BYTE_BGRA);
Ogre::DataStreamPtr encoded = screenshot.encode("jpg");
out.mScreenshot.resize(encoded->size());
encoded->read(&out.mScreenshot[0], encoded->size());
if (fileHeader.mSCRS.size() != 128*128*4)
{
std::cerr << "unexpected screenshot size " << std::endl;
return;
}
osg::ref_ptr<osg::Image> image (new osg::Image);
image->allocateImage(128, 128, 1, GL_RGB, GL_UNSIGNED_BYTE);
// need to convert pixel format from BGRA to RGB as the jpg readerwriter doesn't support it otherwise
std::vector<unsigned char>::const_iterator it = fileHeader.mSCRS.begin();
for (int y=0; y<128; ++y)
{
for (int x=0; x<128; ++x)
{
*(image->data(x,y)+2) = *it++;
*(image->data(x,y)+1) = *it++;
*image->data(x,y) = *it++;
it++; // skip alpha
}
}
image->flipVertical();
std::stringstream ostream;
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
if (!readerwriter)
{
std::cerr << "can't write screenshot: no jpg readerwriter found" << std::endl;
return;
}
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image, ostream);
if (!result.success())
{
std::cerr << "can't write screenshot: " << result.message() << " code " << result.status() << std::endl;
return;
}
std::string data = ostream.str();
out.mScreenshot = std::vector<char>(data.begin(), data.end());
}
}
@ -203,10 +242,6 @@ namespace ESSImport
void Importer::run()
{
// construct Ogre::Root to gain access to image codecs
Ogre::LogManager logman;
Ogre::Root root;
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding));
ESM::ESMReader esm;
esm.open(mEssFile);

@ -89,8 +89,6 @@ add_executable(openmw-launcher
target_link_libraries(openmw-launcher
${Boost_LIBRARIES}
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SDL2_LIBRARY_ONLY}
${QT_LIBRARIES}
components

@ -12,9 +12,6 @@
#include <SDL_video.h>
#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include <boost/math/common_factor.hpp>
#include <components/files/configurationmanager.hpp>
@ -37,10 +34,6 @@ QString getAspect(int x, int y)
Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent)
: QWidget(parent)
, mOgre(NULL)
, mSelectedRenderSystem(NULL)
, mOpenGLRenderSystem(NULL)
, mDirect3DRenderSystem(NULL)
, mCfgMgr(cfg)
, mGraphicsSettings(graphicsSetting)
{
@ -52,79 +45,12 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsS
customWidthSpinBox->setMaximum(res.width());
customHeightSpinBox->setMaximum(res.height());
connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&)));
connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int)));
connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool)));
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
}
bool Launcher::GraphicsPage::setupOgre()
{
try
{
mOgre = mOgreInit.init(mCfgMgr.getLogPath().string() + "/launcherOgre.log");
}
catch(Ogre::Exception &ex)
{
QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str());
QMessageBox msgBox;
msgBox.setWindowTitle("Error creating Ogre::Root");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Failed to create the Ogre::Root object</b><br><br> \
Press \"Show Details...\" for more information.<br>"));
msgBox.setDetailedText(ogreError);
msgBox.exec();
qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError));
return false;
}
// Get the available renderers and put them in the combobox
const Ogre::RenderSystemList &renderers = mOgre->getAvailableRenderers();
for (Ogre::RenderSystemList::const_iterator r = renderers.begin(); r != renderers.end(); ++r) {
mSelectedRenderSystem = *r;
rendererComboBox->addItem((*r)->getName().c_str());
}
QString openGLName = QString("OpenGL Rendering Subsystem");
QString direct3DName = QString("Direct3D9 Rendering Subsystem");
// Create separate rendersystems
mOpenGLRenderSystem = mOgre->getRenderSystemByName(openGLName.toStdString());
mDirect3DRenderSystem = mOgre->getRenderSystemByName(direct3DName.toStdString());
if (!mOpenGLRenderSystem && !mDirect3DRenderSystem) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error creating renderer"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not select a valid render system</b><br><br> \
Please make sure Ogre plugins were installed correctly.<br>"));
msgBox.exec();
return false;
}
// Now fill the GUI elements
int index = rendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system")));
if ( index != -1) {
rendererComboBox->setCurrentIndex(index);
} else {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
rendererComboBox->setCurrentIndex(rendererComboBox->findText(direct3DName));
#else
rendererComboBox->setCurrentIndex(rendererComboBox->findText(openGLName));
#endif
}
antiAliasingComboBox->clear();
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
return true;
}
bool Launcher::GraphicsPage::setupSDL()
{
int displays = SDL_GetNumVideoDisplays();
@ -153,8 +79,6 @@ bool Launcher::GraphicsPage::loadSettings()
{
if (!setupSDL())
return false;
if (!mOgre && !setupOgre())
return false;
if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
vSyncCheckBox->setCheckState(Qt::Checked);
@ -203,7 +127,6 @@ void Launcher::GraphicsPage::saveSettings()
: mGraphicsSettings.setValue(QString("Video/window border"), QString("false"));
mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText());
mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText());
if (standardRadioButton->isChecked()) {
@ -221,39 +144,6 @@ void Launcher::GraphicsPage::saveSettings()
mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex()));
}
QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer)
{
QStringList result;
uint row = 0;
Ogre::ConfigOptionMap options = renderer->getConfigOptions();
for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); ++i, ++row)
{
Ogre::StringVector::iterator opt_it;
uint idx = 0;
for (opt_it = i->second.possibleValues.begin();
opt_it != i->second.possibleValues.end(); ++opt_it, ++idx)
{
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) {
result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromUtf8((*opt_it).c_str()).simplified();
}
}
}
// Sort ascending
qSort(result.begin(), result.end(), naturalSortLessThanCI);
// Replace the zero option with Off
int index = result.indexOf("MSAA 0");
if (index != -1)
result.replace(index, tr("Off"));
return result;
}
QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
{
QStringList result;
@ -316,15 +206,6 @@ QRect Launcher::GraphicsPage::getMaximumResolution()
return max;
}
void Launcher::GraphicsPage::rendererChanged(const QString &renderer)
{
mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString());
antiAliasingComboBox->clear();
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
}
void Launcher::GraphicsPage::screenChanged(int screen)
{
if (screen >= 0) {

@ -3,12 +3,8 @@
#include <QWidget>
#include <components/ogreinit/ogreinit.hpp>
#include "ui_graphicspage.h"
namespace Ogre { class Root; class RenderSystem; }
namespace Files { struct ConfigurationManager; }
namespace Launcher
@ -26,7 +22,6 @@ namespace Launcher
bool loadSettings();
public slots:
void rendererChanged(const QString &renderer);
void screenChanged(int screen);
private slots:
@ -34,20 +29,12 @@ namespace Launcher
void slotStandardToggled(bool checked);
private:
OgreInit::OgreInit mOgreInit;
Ogre::Root *mOgre;
Ogre::RenderSystem *mSelectedRenderSystem;
Ogre::RenderSystem *mOpenGLRenderSystem;
Ogre::RenderSystem *mDirect3DRenderSystem;
Files::ConfigurationManager &mCfgMgr;
GraphicsSettings &mGraphicsSettings;
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
QStringList getAvailableResolutions(int screen);
QRect getMaximumResolution();
bool setupOgre();
bool setupSDL();
};
}

@ -199,7 +199,7 @@ bool Launcher::MainDialog::setup()
// Now create the pages as they need the settings
createPages();
// Call this so we can exit on Ogre/SDL errors before mainwindow is shown
// Call this so we can exit on SDL errors before mainwindow is shown
if (!mGraphicsPage->loadSettings())
return false;
@ -490,7 +490,7 @@ bool Launcher::MainDialog::writeSettings()
// Game settings
QFile file(userPath + QString("openmw.cfg"));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
@ -503,10 +503,8 @@ bool Launcher::MainDialog::writeSettings()
return false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.writeFile(stream);
mGameSettings.writeFileWithComments(file);
file.close();
// Graphics settings
@ -525,6 +523,7 @@ bool Launcher::MainDialog::writeSettings()
return false;
}
QTextStream stream(&file);
stream.setDevice(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));

@ -26,6 +26,7 @@ opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
idcompletionmanager
)
opencs_hdrs_noqt (model/world
@ -68,12 +69,12 @@ opencs_units (view/world
opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator physicssystem
scripthighlighter idvalidator dialoguecreator idcompletiondelegate
)
opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2
scenetooltoggle2 completerpopup
)
opencs_units (view/render
@ -82,8 +83,8 @@ opencs_units (view/render
)
opencs_units_noqt (view/render
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate
lighting lightingday lightingnight
lightingbright object cell terrainstorage
)
opencs_hdrs_noqt (view/render
@ -152,14 +153,14 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE)
endif(WIN32)
set(BOOST_COMPONENTS system filesystem program_options thread wave)
set(BOOST_COMPONENTS system filesystem program_options thread)
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtOpenGL REQUIRED)
include(${QT_USE_FILE})
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
@ -200,13 +201,8 @@ if(APPLE)
endif(APPLE)
target_link_libraries(openmw-cs
${OENGINE_LIBRARY}
${OGRE_LIBRARIES}
${OGRE_Overlay_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES}
${OPENSCENEGRAPH_LIBRARIES}
${Boost_LIBRARIES}
${BULLET_LIBRARIES}
${QT_LIBRARIES}
components
)

@ -1,28 +1,22 @@
#include "editor.hpp"
#include <openengine/bullet/BulletShapeLoader.h>
#include <QApplication>
#include <QLocalServer>
#include <QLocalSocket>
#include <QMessageBox>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
#include <components/vfs/manager.hpp>
#include <components/vfs/registerarchives.hpp>
#include <components/ogreinit/ogreinit.hpp>
#include <components/nifogre/ogrenifloader.hpp>
#include <components/bsa/resources.hpp>
#include <components/nifosg/nifloader.hpp>
#include "model/doc/document.hpp"
#include "model/world/data.hpp"
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
: mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr),
CS::Editor::Editor ()
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr),
mViewManager (mDocumentManager), mPid(""),
mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
{
@ -33,16 +27,13 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
CSMSettings::UserSettings::instance().loadSettings ("opencs.ini");
mSettings.setModel (CSMSettings::UserSettings::instance());
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
NifOsg::Loader::setShowMarkers(true);
NifOgre::Loader::setShowMarkers(true);
mVFS.reset(new VFS::Manager(mFsStrict));
mOverlaySystem.reset (new CSVRender::OverlaySystem);
VFS::registerArchives(mVFS.get(), Files::Collections(config.first, !mFsStrict), config.second, true);
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true,
mFsStrict);
mDocumentManager.listResources();
mDocumentManager.setVFS(mVFS.get());
mNewGame.setLocalData (mLocal);
mFileDialog.setLocalData (mLocal);
@ -81,9 +72,6 @@ CS::Editor::~Editor ()
if(mServer && boost::filesystem::exists(mPid))
static_cast<void> ( // silence coverity warning
remove(mPid.string().c_str())); // ignore any error
// cleanup global resources used by OEngine
delete OEngine::Physic::BulletShapeManager::getSingletonPtr();
}
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
@ -354,114 +342,6 @@ int CS::Editor::run()
return QApplication::exec();
}
std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
{
std::string renderer =
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
"Direct3D9 Rendering Subsystem";
#else
"OpenGL Rendering Subsystem";
#endif
std::string renderSystem = mUserSettings.setting("Video/render system", renderer.c_str()).toStdString();
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName(renderSystem));
// Initialise Ogre::OverlaySystem after Ogre::Root but before initialisation
mOverlaySystem.get();
Ogre::Root::getSingleton().initialise(false);
// Create a hidden background window to keep resources
Ogre::NameValuePairList params;
params.insert(std::make_pair("title", ""));
std::string antialiasing = mUserSettings.settingValue("Video/antialiasing").toStdString();
if(antialiasing == "MSAA 16") antialiasing = "16";
else if(antialiasing == "MSAA 8") antialiasing = "8";
else if(antialiasing == "MSAA 4") antialiasing = "4";
else if(antialiasing == "MSAA 2") antialiasing = "2";
else antialiasing = "0";
params.insert(std::make_pair("FSAA", antialiasing));
params.insert(std::make_pair("vsync", "false"));
params.insert(std::make_pair("hidden", "true"));
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
params.insert(std::make_pair("macAPI", "cocoa"));
#endif
// NOTE: fullscreen mode not supported (doesn't really make sense for opencs)
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, &params);
hiddenWindow->setActive(false);
sh::OgrePlatform* platform =
new sh::OgrePlatform ("General", (mResources / "materials").string());
// for font used in overlays
Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(),
"FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
if (!boost::filesystem::exists (mCfgMgr.getCachePath()))
boost::filesystem::create_directories (mCfgMgr.getCachePath());
platform->setCacheFolder (mCfgMgr.getCachePath().string());
std::auto_ptr<sh::Factory> factory (new sh::Factory (platform));
QString shLang = mUserSettings.settingValue("General/shader mode");
QString rend = renderSystem.c_str();
bool openGL = rend.contains(QRegExp("^OpenGL", Qt::CaseInsensitive));
bool glES = rend.contains(QRegExp("^OpenGL ES", Qt::CaseInsensitive));
// force shader language based on render system
if(shLang == ""
|| (openGL && shLang == "hlsl")
|| (!openGL && shLang == "glsl")
|| (glES && shLang != "glsles"))
{
shLang = openGL ? (glES ? "glsles" : "glsl") : "hlsl";
//no group means "General" group in the "ini" file standard
mUserSettings.setDefinitions("shader mode", (QStringList() << shLang));
}
enum sh::Language lang;
if(shLang == "glsl") lang = sh::Language_GLSL;
else if(shLang == "glsles") lang = sh::Language_GLSLES;
else if(shLang == "hlsl") lang = sh::Language_HLSL;
else lang = sh::Language_CG;
factory->setCurrentLanguage (lang);
factory->setWriteSourceCache (true);
factory->setReadSourceCache (true);
factory->setReadMicrocodeCache (true);
factory->setWriteMicrocodeCache (true);
factory->loadAllFiles();
bool shaders = mUserSettings.setting("3d-render/shaders", QString("true")) == "true" ? true : false;
sh::Factory::getInstance ().setShadersEnabled (shaders);
std::string fog = mUserSettings.setting("Shader/fog", QString("true")).toStdString();
sh::Factory::getInstance().setGlobalSetting ("fog", fog);
std::string shadows = mUserSettings.setting("Shader/shadows", QString("false")).toStdString();
sh::Factory::getInstance().setGlobalSetting ("shadows", shadows);
std::string shadows_pssm = mUserSettings.setting("Shader/shadows_pssm", QString("false")).toStdString();
sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", shadows_pssm);
std::string render_refraction = mUserSettings.setting("Shader/render_refraction", QString("false")).toStdString();
sh::Factory::getInstance ().setGlobalSetting ("render_refraction", render_refraction);
// internal setting - may be switched on or off by the use of shader configurations
sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false");
std::string num_lights = mUserSettings.setting("3d-render-adv/num_lights", QString("8")).toStdString();
sh::Factory::getInstance ().setGlobalSetting ("num_lights", num_lights);
/// \todo add more configurable shiny settings
return factory;
}
void CS::Editor::documentAdded (CSMDoc::Document *document)
{
mViewManager.addView (document);

@ -11,16 +11,12 @@
#include <QLocalServer>
#include <QLocalSocket>
#include <extern/shiny/Main/Factory.hpp>
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
#include <components/files/multidircollection.hpp>
#include <components/nifcache/nifcache.hpp>
#include "model/settings/usersettings.hpp"
#include "model/doc/documentmanager.hpp"
@ -30,11 +26,10 @@
#include "view/doc/newgame.hpp"
#include "view/settings/dialog.hpp"
#include "view/render/overlaysystem.hpp"
namespace OgreInit
namespace VFS
{
class OgreInit;
class Manager;
}
namespace CS
@ -43,10 +38,11 @@ namespace CS
{
Q_OBJECT
Nif::Cache mNifCache;
// FIXME: should be moved to document, so we can have different resources for each opened project
std::auto_ptr<VFS::Manager> mVFS;
Files::ConfigurationManager mCfgMgr;
CSMSettings::UserSettings mUserSettings;
std::auto_ptr<CSVRender::OverlaySystem> mOverlaySystem;
CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup;
@ -71,7 +67,7 @@ namespace CS
public:
Editor (OgreInit::OgreInit& ogreInit);
Editor ();
~Editor ();
bool makeIPCServer();
@ -80,9 +76,6 @@ namespace CS
int run();
///< \return error status
std::auto_ptr<sh::Factory> setupGraphics();
///< The returned factory must persist at least as long as *this.
private slots:
void createGame();

@ -9,10 +9,6 @@
#include <QIcon>
#include <QMetaType>
#include <extern/shiny/Main/Factory.hpp>
#include <components/ogreinit/ogreinit.hpp>
#include "model/world/universalid.hpp"
#ifdef Q_OS_MAC
@ -48,15 +44,14 @@ int main(int argc, char *argv[])
{
try
{
// To allow background thread drawing in OSG
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
Q_INIT_RESOURCE (resources);
qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
OgreInit::OgreInit ogreInit;
std::auto_ptr<sh::Factory> shinyFactory;
Application application (argc, argv);
#ifdef Q_OS_MAC
@ -80,15 +75,13 @@ int main(int argc, char *argv[])
application.setWindowIcon (QIcon (":./openmw-cs.png"));
CS::Editor editor (ogreInit);
CS::Editor editor;
if(!editor.makeIPCServer())
{
editor.connectToIPCServer();
return 0;
}
shinyFactory = editor.setupGraphics();
return editor.run();
}
catch (std::exception& e)

@ -2,6 +2,7 @@
#include <cassert>
#include <fstream>
#include <iostream>
#include <boost/filesystem.hpp>
@ -9,8 +10,6 @@
#include <components/files/configurationmanager.hpp>
#endif
#include "../../view/world/physicssystem.hpp"
void CSMDoc::Document::addGmsts()
{
static const char *gmstFloats[] =
@ -2245,19 +2244,19 @@ void CSMDoc::Document::createBase()
}
}
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
const std::vector<std::string>& blacklistedScripts)
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
mTools (*this),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSavingOperation (*this, mProjectPath, encoding),
mSaving (&mSavingOperation),
mResDir(resDir),
mRunner (mProjectPath), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>())
mRunner (mProjectPath), mIdCompletionManager(mData)
{
if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence");
@ -2313,6 +2312,11 @@ CSMDoc::Document::~Document()
{
}
const VFS::Manager *CSMDoc::Document::getVFS() const
{
return mVFS;
}
QUndoStack& CSMDoc::Document::getUndoStack()
{
return mUndoStack;
@ -2481,10 +2485,7 @@ void CSMDoc::Document::progress (int current, int max, int type)
emit progress (current, max, type, 1, this);
}
boost::shared_ptr<CSVWorld::PhysicsSystem> CSMDoc::Document::getPhysics ()
CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager()
{
if(!mPhysics)
mPhysics = boost::shared_ptr<CSVWorld::PhysicsSystem> (new CSVWorld::PhysicsSystem());
return mPhysics;
return mIdCompletionManager;
}

@ -13,6 +13,7 @@
#include <components/to_utf8/to_utf8.hpp>
#include "../world/data.hpp"
#include "../world/idcompletionmanager.hpp"
#include "../tools/tools.hpp"
@ -24,6 +25,12 @@
class QAbstractItemModel;
namespace VFS
{
class Manager;
}
namespace ESM
{
struct GameSetting;
@ -41,11 +48,6 @@ namespace CSMWorld
class ResourcesManager;
}
namespace CSVWorld
{
class PhysicsSystem;
}
namespace CSMDoc
{
class Document : public QObject
@ -54,6 +56,7 @@ namespace CSMDoc
private:
const VFS::Manager* mVFS;
boost::filesystem::path mSavePath;
std::vector<boost::filesystem::path> mContentFiles;
bool mNew;
@ -65,7 +68,8 @@ namespace CSMDoc
boost::filesystem::path mResDir;
Blacklist mBlacklist;
Runner mRunner;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
CSMWorld::IdCompletionManager mIdCompletionManager;
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
// using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
@ -93,7 +97,7 @@ namespace CSMDoc
public:
Document (const Files::ConfigurationManager& configuration,
Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
@ -101,6 +105,8 @@ namespace CSMDoc
~Document();
const VFS::Manager* getVFS() const;
QUndoStack& getUndoStack();
int getState() const;
@ -142,7 +148,7 @@ namespace CSMDoc
QTextDocument *getRunLog();
boost::shared_ptr<CSVWorld::PhysicsSystem> getPhysics();
CSMWorld::IdCompletionManager &getIdCompletionManager();
signals:

@ -13,7 +13,7 @@
#include "document.hpp"
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252)
: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mVFS(NULL)
{
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
@ -57,7 +57,7 @@ bool CSMDoc::DocumentManager::isEmpty()
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
bool new_)
{
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
Document *document = new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
mDocuments.push_back (document);
@ -95,11 +95,6 @@ void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector<std::stri
mBlacklistedScripts = scriptIds;
}
void CSMDoc::DocumentManager::listResources()
{
mResourcesManager.listResources();
}
void CSMDoc::DocumentManager::documentLoaded (Document *document)
{
emit documentAdded (document);
@ -113,3 +108,9 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std::
if (error.empty()) // do not remove the document yet, if we have an error
removeDocument (document);
}
void CSMDoc::DocumentManager::setVFS(const VFS::Manager *vfs)
{
mResourcesManager.setVFS(vfs);
mVFS = vfs;
}

@ -15,6 +15,11 @@
#include "loader.hpp"
namespace VFS
{
class Manager;
}
namespace Files
{
struct ConfigurationManager;
@ -35,6 +40,7 @@ namespace CSMDoc
ToUTF8::FromType mEncoding;
CSMWorld::ResourcesManager mResourcesManager;
std::vector<std::string> mBlacklistedScripts;
const VFS::Manager* mVFS;
DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&);
@ -56,8 +62,7 @@ namespace CSMDoc
void setBlacklistedScripts (const std::vector<std::string>& scriptIds);
/// Ask OGRE for a list of available resources.
void listResources();
void setVFS(const VFS::Manager* vfs);
bool isEmpty();

@ -12,8 +12,6 @@
#include <QTextCodec>
#include <QDebug>
#include <extern/shiny/Main/Factory.hpp>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
@ -44,13 +42,9 @@ CSMSettings::UserSettings *CSMSettings::UserSettings::sUserSettingsInstance = 0;
void CSMSettings::UserSettings::buildSettingModelDefaults()
{
QString section;
/*
declareSection ("3d-render", "3D Rendering");
{
Setting *shaders = createSetting (Type_CheckBox, "shaders", "Enable Shaders");
shaders->setDefaultValue ("true");
Setting *farClipDist = createSetting (Type_DoubleSpinBox, "far-clip-distance", "Far clipping distance");
farClipDist->setDefaultValue (300000);
farClipDist->setRange (0, 1000000);
@ -62,23 +56,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
<< defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16");
antialiasing->setDefaultValue (defaultValue);
}
*/
declareSection ("3d-render-adv", "3D Rendering (Advanced)");
{
Setting *numLights = createSetting (Type_SpinBox, "num_lights",
"Number of lights per pass");
numLights->setDefaultValue (8);
numLights->setRange (1, 100);
}
/*
declareSection ("scene-input", "Scene Input");
{
Setting *timer = createSetting (Type_SpinBox, "timer", "Input responsiveness");
timer->setDefaultValue (20);
timer->setRange (1, 100);
timer->setToolTip ("The time between two checks for user input in milliseconds.<p>"
"Lower value result in higher responsiveness.");
Setting *fastFactor = createSetting (Type_SpinBox, "fast-factor",
"Fast movement factor");
fastFactor->setDefaultValue (4);
@ -86,6 +68,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
fastFactor->setToolTip (
"Factor by which movement is speed up while the shift key is held down.");
}
*/
declareSection ("window", "Window");
{
@ -562,15 +545,6 @@ void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey,
{
mSettingDefinitions->setValue (settingKey ,list);
if(settingKey == "3d-render-adv/num_lights" && !list.empty())
{
sh::Factory::getInstance ().setGlobalSetting ("num_lights", list.at(0).toStdString());
}
else if(settingKey == "3d-render/shaders" && !list.empty())
{
sh::Factory::getInstance ().setShadersEnabled (list.at(0).toStdString() == "true" ? true : false);
}
emit userSettingUpdated (settingKey, list);
}

@ -65,6 +65,8 @@ bool CSMWorld::ColumnBase::isId (Display display)
Display_JournalInfo,
Display_Scene,
Display_GlobalVariable,
Display_BodyPart,
Display_Enchantment,
Display_Script,
Display_Mesh,

@ -74,6 +74,8 @@ namespace CSMWorld
Display_JournalInfo,
Display_Scene,
Display_GlobalVariable,
Display_BodyPart,
Display_Enchantment,
//CONCRETE TYPES ENDS HERE
Display_Integer,

@ -709,7 +709,7 @@ namespace CSMWorld
struct SleepListColumn : public Column<ESXRecordT>
{
SleepListColumn()
: Column<ESXRecordT> (Columns::ColumnId_SleepEncounter, ColumnBase::Display_String)
: Column<ESXRecordT> (Columns::ColumnId_SleepEncounter, ColumnBase::Display_CreatureLevelledList)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
@ -735,7 +735,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct TextureColumn : public Column<ESXRecordT>
{
TextureColumn() : Column<ESXRecordT> (Columns::ColumnId_Texture, ColumnBase::Display_String) {}
TextureColumn() : Column<ESXRecordT> (Columns::ColumnId_Texture, ColumnBase::Display_Texture) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -1269,7 +1269,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct TrapColumn : public Column<ESXRecordT>
{
TrapColumn() : Column<ESXRecordT> (Columns::ColumnId_Trap, ColumnBase::Display_String) {}
TrapColumn() : Column<ESXRecordT> (Columns::ColumnId_Trap, ColumnBase::Display_Spell) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -1294,7 +1294,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct FilterColumn : public Column<ESXRecordT>
{
FilterColumn() : Column<ESXRecordT> (Columns::ColumnId_Filter, ColumnBase::Display_String) {}
FilterColumn() : Column<ESXRecordT> (Columns::ColumnId_Filter, ColumnBase::Display_Filter) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -1497,7 +1497,10 @@ namespace CSMWorld
template<typename ESXRecordT>
struct TopicColumn : public Column<ESXRecordT>
{
TopicColumn (bool journal) : Column<ESXRecordT> (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, ColumnBase::Display_String) {}
TopicColumn (bool journal)
: Column<ESXRecordT> (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic,
journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -1527,7 +1530,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct ActorColumn : public Column<ESXRecordT>
{
ActorColumn() : Column<ESXRecordT> (Columns::ColumnId_Actor, ColumnBase::Display_String) {}
ActorColumn() : Column<ESXRecordT> (Columns::ColumnId_Actor, ColumnBase::Display_Npc) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -1830,7 +1833,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct ModelColumn : public Column<ESXRecordT>
{
ModelColumn() : Column<ESXRecordT> (Columns::ColumnId_Model, ColumnBase::Display_String) {}
ModelColumn() : Column<ESXRecordT> (Columns::ColumnId_Model, ColumnBase::Display_Mesh) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -2158,7 +2161,9 @@ namespace CSMWorld
struct EffectTextureColumn : public Column<ESXRecordT>
{
EffectTextureColumn (Columns::ColumnId columnId)
: Column<ESXRecordT> (columnId, ColumnBase::Display_Texture)
: Column<ESXRecordT> (columnId,
columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture
: ColumnBase::Display_Icon)
{
assert (this->mColumnId==Columns::ColumnId_Icon ||
this->mColumnId==Columns::ColumnId_Particle);

@ -62,7 +62,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager)
: mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0)
mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(resourcesManager.getVFS())
{
int index = 0;
@ -115,7 +115,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
index = mFactions.getColumns()-1;
mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ()));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String));
new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer));
@ -135,7 +135,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
index = mRaces.getColumns()-1;
mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter<ESM::Race> ()));
mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String));
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell));
// Race attributes
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceAttributes));
index = mRaces.getColumns()-1;
@ -180,7 +180,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
index = mRegions.getColumns()-1;
mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ()));
mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String));
new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_Sound));
mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer));
@ -196,7 +196,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index),
new SpellListAdapter<ESM::BirthSign> ()));
mBirthsigns.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String));
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell));
mSpells.addColumn (new StringIdColumn<ESM::Spell>);
mSpells.addColumn (new RecordStateColumn<ESM::Spell>);
@ -527,6 +527,16 @@ CSMWorld::Data::~Data()
delete mReader;
}
Resource::ResourceSystem* CSMWorld::Data::getResourceSystem()
{
return &mResourceSystem;
}
const Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() const
{
return &mResourceSystem;
}
const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const
{
return mGlobals;
@ -1159,3 +1169,8 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end)
{
emit idListChanged();
}
const VFS::Manager* CSMWorld::Data::getVFS() const
{
return mResourcesManager.getVFS();
}

@ -29,6 +29,8 @@
#include <components/esm/debugprofile.hpp>
#include <components/esm/filter.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/to_utf8/to_utf8.hpp>
#include "../doc/stage.hpp"
@ -50,6 +52,11 @@
class QAbstractItemModel;
namespace VFS
{
class Manager;
}
namespace ESM
{
class ESMReader;
@ -106,6 +113,8 @@ namespace CSMWorld
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
int mReaderIndex;
Resource::ResourceSystem mResourceSystem;
std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders;
// not implemented
@ -127,6 +136,12 @@ namespace CSMWorld
virtual ~Data();
const VFS::Manager* getVFS() const;
Resource::ResourceSystem* getResourceSystem();
const Resource::ResourceSystem* getResourceSystem() const;
const IdCollection<ESM::Global>& getGlobals() const;
IdCollection<ESM::Global>& getGlobals();

@ -0,0 +1,110 @@
#include "idcompletionmanager.hpp"
#include <boost/make_shared.hpp>
#include <QCompleter>
#include "../../view/widget/completerpopup.hpp"
#include "data.hpp"
#include "idtablebase.hpp"
namespace
{
std::map<CSMWorld::ColumnBase::Display, CSMWorld::UniversalId::Type> generateModelTypes()
{
std::map<CSMWorld::ColumnBase::Display, CSMWorld::UniversalId::Type> types;
types[CSMWorld::ColumnBase::Display_BodyPart ] = CSMWorld::UniversalId::Type_BodyPart;
types[CSMWorld::ColumnBase::Display_Cell ] = CSMWorld::UniversalId::Type_Cell;
types[CSMWorld::ColumnBase::Display_Class ] = CSMWorld::UniversalId::Type_Class;
types[CSMWorld::ColumnBase::Display_CreatureLevelledList] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Creature ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Enchantment ] = CSMWorld::UniversalId::Type_Enchantment;
types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction;
types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global;
types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon;
types[CSMWorld::ColumnBase::Display_Mesh ] = CSMWorld::UniversalId::Type_Mesh;
types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Npc ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Race ] = CSMWorld::UniversalId::Type_Race;
types[CSMWorld::ColumnBase::Display_Region ] = CSMWorld::UniversalId::Type_Region;
types[CSMWorld::ColumnBase::Display_Referenceable ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Script ] = CSMWorld::UniversalId::Type_Script;
types[CSMWorld::ColumnBase::Display_Skill ] = CSMWorld::UniversalId::Type_Skill;
types[CSMWorld::ColumnBase::Display_Sound ] = CSMWorld::UniversalId::Type_Sound;
types[CSMWorld::ColumnBase::Display_SoundRes ] = CSMWorld::UniversalId::Type_SoundRes;
types[CSMWorld::ColumnBase::Display_Spell ] = CSMWorld::UniversalId::Type_Spell;
types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture;
types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable;
return types;
}
typedef std::map<CSMWorld::ColumnBase::Display,
CSMWorld::UniversalId::Type>::const_iterator ModelTypeConstIterator;
}
const std::map<CSMWorld::ColumnBase::Display, CSMWorld::UniversalId::Type>
CSMWorld::IdCompletionManager::sCompleterModelTypes = generateModelTypes();
std::vector<CSMWorld::ColumnBase::Display> CSMWorld::IdCompletionManager::getDisplayTypes()
{
std::vector<CSMWorld::ColumnBase::Display> types;
ModelTypeConstIterator current = sCompleterModelTypes.begin();
ModelTypeConstIterator end = sCompleterModelTypes.end();
for (; current != end; ++current)
{
types.push_back(current->first);
}
return types;
}
CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data)
{
generateCompleters(data);
}
bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::ColumnBase::Display display) const
{
return mCompleters.find(display) != mCompleters.end();
}
boost::shared_ptr<QCompleter> CSMWorld::IdCompletionManager::getCompleter(CSMWorld::ColumnBase::Display display)
{
if (!hasCompleterFor(display))
{
throw std::logic_error("This column doesn't have an ID completer");
}
return mCompleters[display];
}
void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data)
{
ModelTypeConstIterator current = sCompleterModelTypes.begin();
ModelTypeConstIterator end = sCompleterModelTypes.end();
for (; current != end; ++current)
{
QAbstractItemModel *model = data.getTableModel(current->second);
CSMWorld::IdTableBase *table = dynamic_cast<CSMWorld::IdTableBase *>(model);
if (table != NULL)
{
int idColumn = table->searchColumnIndex(CSMWorld::Columns::ColumnId_Id);
if (idColumn != -1)
{
boost::shared_ptr<QCompleter> completer = boost::make_shared<QCompleter>(table);
completer->setCompletionColumn(idColumn);
// The completion role must be Qt::DisplayRole to get the ID values from the model
completer->setCompletionRole(Qt::DisplayRole);
completer->setCaseSensitivity(Qt::CaseInsensitive);
QAbstractItemView *popup = new CSVWidget::CompleterPopup();
completer->setPopup(popup); // The completer takes ownership of the popup
completer->setMaxVisibleItems(10);
mCompleters[current->first] = completer;
}
}
}
}

@ -0,0 +1,41 @@
#ifndef CSM_WORLD_IDCOMPLETIONMANAGER_HPP
#define CSM_WORLD_IDCOMPLETIONMANAGER_HPP
#include <vector>
#include <map>
#include <boost/shared_ptr.hpp>
#include "columnbase.hpp"
#include "universalid.hpp"
class QCompleter;
namespace CSMWorld
{
class Data;
/// \brief Creates and stores all ID completers
class IdCompletionManager
{
static const std::map<ColumnBase::Display, UniversalId::Type> sCompleterModelTypes;
std::map<ColumnBase::Display, boost::shared_ptr<QCompleter> > mCompleters;
// Don't allow copying
IdCompletionManager(const IdCompletionManager &);
IdCompletionManager &operator = (const IdCompletionManager &);
void generateCompleters(Data &data);
public:
static std::vector<ColumnBase::Display> getDisplayTypes();
IdCompletionManager(Data &data);
bool hasCompleterFor(ColumnBase::Display display) const;
boost::shared_ptr<QCompleter> getCompleter(ColumnBase::Display display);
};
}
#endif

@ -33,6 +33,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
if (index.row() < 0 || index.column() < 0)
return QVariant();
if (role==ColumnBase::Role_Display)
return QVariant(mIdCollection->getColumn(index.column()).mDisplayType);
if (role==ColumnBase::Role_ColumnId)
return QVariant (getColumnId (index.column()));
@ -84,6 +87,9 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value
Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const
{
if (!index.isValid())
return 0;
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (mIdCollection->getColumn (index.column()).isUserEditable())

@ -21,6 +21,18 @@ void CSMWorld::IdTableProxyModel::updateColumnMap()
}
}
bool CSMWorld::IdTableProxyModel::filterAcceptsColumn (int sourceColumn, const QModelIndex& sourceParent)
const
{
int flags =
sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
if (flags & CSMWorld::ColumnBase::Flag_Table)
return true;
else
return false;
}
bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent)
const
{

@ -24,8 +24,6 @@ namespace CSMWorld
void updateColumnMap();
bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const;
public:
IdTableProxyModel (QObject *parent = 0);
@ -39,6 +37,10 @@ namespace CSMWorld
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const;
virtual bool filterAcceptsColumn (int sourceColumn, const QModelIndex& sourceParent) const;
};
}

@ -35,28 +35,29 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const
if (!index.isValid())
return QVariant();
if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0)
return QVariant();
if (index.internalId() != 0)
{
std::pair<int, int> parentAddress(unfoldIndexAddress(index.internalId()));
const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second);
if (role == Qt::EditRole &&
!mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable())
{
if (role == ColumnBase::Role_Display)
return parentColumn->nestedColumn(index.column()).mDisplayType;
if (role == ColumnBase::Role_ColumnId)
return parentColumn->nestedColumn(index.column()).mColumnId;
if (role == Qt::EditRole && !parentColumn->nestedColumn(index.column()).isEditable())
return QVariant();
if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();
}
return mNestedCollection->getNestedData(parentAddress.first,
parentAddress.second, index.row(), index.column());
}
else
{
if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable())
return QVariant();
return idCollection()->getData (index.row(), index.column());
return IdTable::data(index, role);
}
}
@ -79,6 +80,9 @@ QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Ori
if (role==ColumnBase::Role_Display)
return parentColumn->nestedColumn(subSection).mDisplayType;
if (role==ColumnBase::Role_ColumnId)
return parentColumn->nestedColumn(subSection).mColumnId;
return QVariant();
}

@ -906,7 +906,7 @@ namespace CSMWorld
NestedTableWrapperBase* RaceAttributeAdapter::table(const Record<ESM::Race>& record) const
{
std::vector<typename ESM::Race::RADTstruct> wrap;
std::vector<ESM::Race::RADTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct> >(wrap);
@ -983,7 +983,7 @@ namespace CSMWorld
NestedTableWrapperBase* RaceSkillsBonusAdapter::table(const Record<ESM::Race>& record) const
{
std::vector<typename ESM::Race::RADTstruct> wrap;
std::vector<ESM::Race::RADTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct> >(wrap);

@ -576,7 +576,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* col
// store the whole struct
npc.mNpdt52 =
static_cast<const NestedTableWrapper<std::vector<typename ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
record.setModified (npc);
}
@ -588,10 +588,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTab
static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
// return the whole struct
std::vector<typename ESM::NPC::NPDTstruct52> wrap;
std::vector<ESM::NPC::NPDTstruct52> wrap;
wrap.push_back(record.get().mNpdt52);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<typename ESM::NPC::NPDTstruct52> >(wrap);
return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> >(wrap);
}
QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *column,
@ -694,7 +694,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column,
// store the whole struct
npc.mNpdt52 =
static_cast<const NestedTableWrapper<std::vector<typename ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
record.setModified (npc);
}
@ -706,10 +706,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable (
static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
// return the whole struct
std::vector<typename ESM::NPC::NPDTstruct52> wrap;
std::vector<ESM::NPC::NPDTstruct52> wrap;
wrap.push_back(record.get().mNpdt52);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<typename ESM::NPC::NPDTstruct52> >(wrap);
return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> >(wrap);
}
QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *column,

@ -99,7 +99,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
EnchantableColumns enchantableColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_String));
mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_Enchantment));
enchantableColumns.mEnchantment = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer));
enchantableColumns.mEnchantmentPoints = &mColumns.back();
@ -135,7 +135,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedInventoryRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
@ -150,7 +150,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedSpellRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations,
@ -163,7 +163,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedTravelRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn(
@ -289,7 +289,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedInventoryRefIdAdapter<ESM::Container> (UniversalId::Type_Container)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
@ -301,7 +301,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
creatureColumns.mSoul = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float));
creatureColumns.mScale = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_String));
mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature));
creatureColumns.mOriginal = &mColumns.back();
mColumns.push_back (
RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer));
@ -409,10 +409,10 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction));
npcColumns.mFaction = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String));
mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_BodyPart));
npcColumns.mHair = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_String));
mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart));
npcColumns.mHead = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Female, ColumnBase::Display_Boolean));
@ -539,9 +539,9 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_BodyPart));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_BodyPart));
LevListColumns levListColumns (baseColumns);
@ -556,7 +556,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedLevListRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer));

@ -5,61 +5,49 @@
#include <stdexcept>
#include <algorithm>
#include <OgreResourceGroupManager.h>
#include <components/vfs/manager.hpp>
#include <components/misc/stringops.hpp>
CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::Type type,
CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type,
const char * const *extensions)
: mBaseDirectory (baseDirectory), mType (type)
{
int baseSize = mBaseDirectory.size();
Ogre::StringVector resourcesGroups =
Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
for (Ogre::StringVector::iterator iter (resourcesGroups.begin());
iter!=resourcesGroups.end(); ++iter)
const std::map<std::string, VFS::File*>& index = vfs->getIndex();
for (std::map<std::string, VFS::File*>::const_iterator it = index.begin(); it != index.end(); ++it)
{
if (*iter=="General" || *iter=="Internal" || *iter=="Autodetect")
std::string filepath = it->first;
if (static_cast<int> (filepath.size())<baseSize+1 ||
filepath.substr (0, baseSize)!=mBaseDirectory ||
(filepath[baseSize]!='/' && filepath[baseSize]!='\\'))
continue;
Ogre::StringVectorPtr resources =
Ogre::ResourceGroupManager::getSingleton().listResourceNames (*iter);
for (Ogre::StringVector::const_iterator iter (resources->begin());
iter!=resources->end(); ++iter)
if (extensions)
{
if (static_cast<int> (iter->size())<baseSize+1 ||
iter->substr (0, baseSize)!=mBaseDirectory ||
((*iter)[baseSize]!='/' && (*iter)[baseSize]!='\\'))
continue;
if (extensions)
{
std::string::size_type index = iter->find_last_of ('.');
std::string::size_type index = filepath.find_last_of ('.');
if (index==std::string::npos)
continue;
std::string extension = iter->substr (index+1);
if (index==std::string::npos)
continue;
int i = 0;
std::string extension = filepath.substr (index+1);
for (; extensions[i]; ++i)
if (extensions[i]==extension)
break;
int i = 0;
if (!extensions[i])
continue;
}
for (; extensions[i]; ++i)
if (extensions[i]==extension)
break;
std::string file = iter->substr (baseSize+1);
mFiles.push_back (file);
std::replace (file.begin(), file.end(), '\\', '/');
mIndex.insert (std::make_pair (
Misc::StringUtils::lowerCase (file), static_cast<int> (mFiles.size())-1));
if (!extensions[i])
continue;
}
std::string file = filepath.substr (baseSize+1);
mFiles.push_back (file);
std::replace (file.begin(), file.end(), '\\', '/');
mIndex.insert (std::make_pair (
Misc::StringUtils::lowerCase (file), static_cast<int> (mFiles.size())-1));
}
}

@ -7,6 +7,11 @@
#include "universalid.hpp"
namespace VFS
{
class Manager;
}
namespace CSMWorld
{
class Resources
@ -19,7 +24,7 @@ namespace CSMWorld
public:
/// \param type Type of resources in this table.
Resources (const std::string& baseDirectory, UniversalId::Type type,
Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type,
const char * const *extensions = 0);
int getSize() const;

@ -3,6 +3,11 @@
#include <stdexcept>
CSMWorld::ResourcesManager::ResourcesManager()
: mVFS(NULL)
{
}
void CSMWorld::ResourcesManager::addResources (const Resources& resources)
{
mResources.insert (std::make_pair (resources.getType(), resources));
@ -10,16 +15,24 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources)
resources));
}
void CSMWorld::ResourcesManager::listResources()
void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs)
{
mVFS = vfs;
mResources.clear();
static const char * const sMeshTypes[] = { "nif", 0 };
addResources (Resources ("meshes", UniversalId::Type_Mesh, sMeshTypes));
addResources (Resources ("icons", UniversalId::Type_Icon));
addResources (Resources ("music", UniversalId::Type_Music));
addResources (Resources ("sound", UniversalId::Type_SoundRes));
addResources (Resources ("textures", UniversalId::Type_Texture));
addResources (Resources ("videos", UniversalId::Type_Video));
addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes));
addResources (Resources (vfs, "icons", UniversalId::Type_Icon));
addResources (Resources (vfs, "music", UniversalId::Type_Music));
addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes));
addResources (Resources (vfs, "textures", UniversalId::Type_Texture));
addResources (Resources (vfs, "videos", UniversalId::Type_Video));
}
const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const
{
return mVFS;
}
const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const

@ -6,11 +6,17 @@
#include "universalid.hpp"
#include "resources.hpp"
namespace VFS
{
class Manager;
}
namespace CSMWorld
{
class ResourcesManager
{
std::map<UniversalId::Type, Resources> mResources;
const VFS::Manager* mVFS;
private:
@ -18,8 +24,11 @@ namespace CSMWorld
public:
/// Ask OGRE for a list of available resources.
void listResources();
ResourcesManager();
const VFS::Manager* getVFS() const;
void setVFS(const VFS::Manager* vfs);
const Resources& get (UniversalId::Type type) const;
};

@ -1,6 +1,7 @@
#include "viewmanager.hpp"
#include <vector>
#include <map>
#include <QApplication>
@ -10,12 +11,14 @@
#include "../../model/doc/document.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/universalid.hpp"
#include "../../model/world/idcompletionmanager.hpp"
#include "../world/util.hpp"
#include "../world/enumdelegate.hpp"
#include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp"
#include "../world/idcompletiondelegate.hpp"
#include "../../model/settings/usersettings.hpp"
@ -60,6 +63,14 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
new CSVWorld::IdTypeDelegateFactory());
std::vector<CSMWorld::ColumnBase::Display> idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes();
for (std::vector<CSMWorld::ColumnBase::Display>::const_iterator current = idCompletionColumns.begin();
current != idCompletionColumns.end();
++current)
{
mDelegateFactories->add(*current, new CSVWorld::IdCompletionDelegateFactory());
}
struct Mapping
{
CSMWorld::ColumnBase::Display mDisplay;

@ -1,8 +1,7 @@
#include "cell.hpp"
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <osg/Group>
#include <components/misc/stringops.hpp>
#include <components/esm/loadland.hpp>
@ -11,7 +10,6 @@
#include "../../model/world/columns.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/refcollection.hpp"
#include "../world/physicssystem.hpp"
#include "elements.hpp"
#include "terrainstorage.hpp"
@ -45,7 +43,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
{
std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId);
mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics)));
mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false)));
modified = true;
}
}
@ -53,12 +51,11 @@ bool CSVRender::Cell::addObjects (int start, int end)
return modified;
}
CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin)
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mPhysics(physics), mSceneMgr(sceneManager), mX(0), mY(0)
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id)
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0)
{
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
mCellNode->setPosition (origin);
mCellNode = new osg::Group;
rootNode->addChild(mCellNode);
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
@ -74,31 +71,23 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT)
{
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true,
Terrain::Align_XY));
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
mTerrain->loadCell(esmLand->mX,
esmLand->mY);
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
mX = esmLand->mX;
mY = esmLand->mY;
mPhysics->addHeightField(sceneManager,
esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts);
}
}
}
CSVRender::Cell::~Cell()
{
if (mTerrain.get())
mPhysics->removeHeightField(mSceneMgr, mX, mY);
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
delete iter->second;
mCellNode->getCreator()->destroySceneNode (mCellNode);
mCellNode->getParent(0)->removeChild(mCellNode);
}
bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft,
@ -186,7 +175,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
for (std::map<std::string, bool>::iterator iter (ids.begin()); iter!=ids.end(); ++iter)
{
mObjects.insert (std::make_pair (
iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics)));
iter->first, new Object (mData, mCellNode, iter->first, false)));
modified = true;
}
@ -222,11 +211,3 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int
return addObjects (start, end);
}
float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const
{
if(mTerrain.get() != NULL)
return mTerrain->getHeightAt(pos);
else
return -std::numeric_limits<float>::max();
}

@ -7,7 +7,7 @@
#include <boost/shared_ptr.hpp>
#include <OgreVector3.h>
#include <osg/ref_ptr>
#ifndef Q_MOC_RUN
#include <components/terrain/terraingrid.hpp>
@ -17,10 +17,9 @@
class QModelIndex;
namespace Ogre
namespace osg
{
class SceneManager;
class SceneNode;
class Group;
}
namespace CSMWorld
@ -28,22 +27,15 @@ namespace CSMWorld
class Data;
}
namespace CSVWorld
{
class PhysicsSystem;
}
namespace CSVRender
{
class Cell
{
CSMWorld::Data& mData;
std::string mId;
Ogre::SceneNode *mCellNode;
osg::ref_ptr<osg::Group> mCellNode;
std::map<std::string, Object *> mObjects;
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
Ogre::SceneManager *mSceneMgr;
int mX;
int mY;
@ -59,8 +51,7 @@ namespace CSVRender
public:
Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id,
boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0));
Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id);
~Cell();
@ -84,8 +75,6 @@ namespace CSVRender
/// \return Did this call result in a modification of the visual representation of
/// this cell?
bool referenceAdded (const QModelIndex& parent, int start, int end);
float getTerrainHeightAt(const Ogre::Vector3 &pos) const;
};
}

@ -1,4 +1,5 @@
#include "lighting.hpp"
#include <osg/LightSource>
CSVRender::Lighting::~Lighting() {}

@ -1,10 +1,13 @@
#ifndef OPENCS_VIEW_LIGHTING_H
#define OPENCS_VIEW_LIGHTING_H
namespace Ogre
#include <osg/ref_ptr>
namespace osg
{
class SceneManager;
class ColourValue;
class Vec4f;
class LightSource;
class Group;
}
namespace CSVRender
@ -13,14 +16,19 @@ namespace CSVRender
{
public:
Lighting() : mRootNode(0) {}
virtual ~Lighting();
virtual void activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient = 0) = 0;
virtual void activate (osg::Group* rootNode) = 0;
virtual void deactivate() = 0;
virtual void setDefaultAmbient (const Ogre::ColourValue& colour) = 0;
virtual osg::Vec4f getAmbientColour(osg::Vec4f* defaultAmbient) = 0;
protected:
osg::ref_ptr<osg::LightSource> mLightSource;
osg::Group* mRootNode;
};
}

@ -1,30 +1,35 @@
#include "lightingbright.hpp"
#include <OgreSceneManager.h>
#include <osg/LightSource>
CSVRender::LightingBright::LightingBright() : mSceneManager (0), mLight (0) {}
CSVRender::LightingBright::LightingBright() {}
void CSVRender::LightingBright::activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient)
void CSVRender::LightingBright::activate (osg::Group* rootNode)
{
mSceneManager = sceneManager;
mRootNode = rootNode;
mSceneManager->setAmbientLight (Ogre::ColourValue (1.0, 1.0, 1.0, 1));
mLightSource = (new osg::LightSource);
mLight = mSceneManager->createLight();
mLight->setType (Ogre::Light::LT_DIRECTIONAL);
mLight->setDirection (Ogre::Vector3 (0, 0, -1));
mLight->setDiffuseColour (Ogre::ColourValue (1.0, 1.0, 1.0));
osg::ref_ptr<osg::Light> light (new osg::Light);
light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f));
light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f));
light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f));
light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f));
light->setConstantAttenuation(1.f);
mLightSource->setLight(light);
mRootNode->addChild(mLightSource);
}
void CSVRender::LightingBright::deactivate()
{
if (mLight)
{
mSceneManager->destroyLight (mLight);
mLight = 0;
}
if (mRootNode && mLightSource.get())
mRootNode->removeChild(mLightSource);
}
void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {}
osg::Vec4f CSVRender::LightingBright::getAmbientColour(osg::Vec4f* /*defaultAmbient*/)
{
return osg::Vec4f(1.f, 1.f, 1.f, 1.f);
}

@ -3,28 +3,25 @@
#include "lighting.hpp"
namespace Ogre
namespace osg
{
class Light;
class Group;
}
namespace CSVRender
{
class LightingBright : public Lighting
{
Ogre::SceneManager *mSceneManager;
Ogre::Light *mLight;
public:
LightingBright();
virtual void activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient = 0);
virtual void activate (osg::Group* rootNode);
virtual void deactivate();
virtual void setDefaultAmbient (const Ogre::ColourValue& colour);
virtual osg::Vec4f getAmbientColour(osg::Vec4f* defaultAmbient);
};
}

@ -1,36 +1,36 @@
#include "lightingday.hpp"
#include <OgreSceneManager.h>
#include <osg/LightSource>
CSVRender::LightingDay::LightingDay() : mSceneManager (0), mLight (0) {}
CSVRender::LightingDay::LightingDay(){}
void CSVRender::LightingDay::activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient)
void CSVRender::LightingDay::activate (osg::Group* rootNode)
{
mSceneManager = sceneManager;
mRootNode = rootNode;
if (defaultAmbient)
mSceneManager->setAmbientLight (*defaultAmbient);
else
mSceneManager->setAmbientLight (Ogre::ColourValue (0.7, 0.7, 0.7, 1));
mLightSource = new osg::LightSource;
mLight = mSceneManager->createLight();
mLight->setType (Ogre::Light::LT_DIRECTIONAL);
mLight->setDirection (Ogre::Vector3 (0, 0, -1));
mLight->setDiffuseColour (Ogre::ColourValue (1, 1, 1));
osg::ref_ptr<osg::Light> light (new osg::Light);
light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f));
light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f));
light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f));
light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f));
light->setConstantAttenuation(1.f);
mLightSource->setLight(light);
mRootNode->addChild(mLightSource);
}
void CSVRender::LightingDay::deactivate()
{
if (mLight)
{
mSceneManager->destroyLight (mLight);
mLight = 0;
}
if (mRootNode && mLightSource.get())
mRootNode->removeChild(mLightSource);
}
void CSVRender::LightingDay::setDefaultAmbient (const Ogre::ColourValue& colour)
osg::Vec4f CSVRender::LightingDay::getAmbientColour(osg::Vec4f *defaultAmbient)
{
mSceneManager->setAmbientLight (colour);
if (defaultAmbient)
return *defaultAmbient;
else
return osg::Vec4f(0.7f, 0.7f, 0.7f, 1.f);
}

@ -3,28 +3,19 @@
#include "lighting.hpp"
namespace Ogre
{
class Light;
}
namespace CSVRender
{
class LightingDay : public Lighting
{
Ogre::SceneManager *mSceneManager;
Ogre::Light *mLight;
public:
LightingDay();
virtual void activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient = 0);
virtual void activate (osg::Group* rootNode);
virtual void deactivate();
virtual void setDefaultAmbient (const Ogre::ColourValue& colour);
virtual osg::Vec4f getAmbientColour(osg::Vec4f *defaultAmbient);
};
}

@ -1,36 +1,37 @@
#include "lightingnight.hpp"
#include <OgreSceneManager.h>
#include <osg/LightSource>
CSVRender::LightingNight::LightingNight() : mSceneManager (0), mLight (0) {}
CSVRender::LightingNight::LightingNight() {}
void CSVRender::LightingNight::activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient)
void CSVRender::LightingNight::activate (osg::Group* rootNode)
{
mSceneManager = sceneManager;
mRootNode = rootNode;
if (defaultAmbient)
mSceneManager->setAmbientLight (*defaultAmbient);
else
mSceneManager->setAmbientLight (Ogre::ColourValue (0.2, 0.2, 0.2, 1));
mLightSource = new osg::LightSource;
osg::ref_ptr<osg::Light> light (new osg::Light);
light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f));
light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f));
light->setDiffuse(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f));
light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f));
light->setConstantAttenuation(1.f);
mLight = mSceneManager->createLight();
mLight->setType (Ogre::Light::LT_DIRECTIONAL);
mLight->setDirection (Ogre::Vector3 (0, 0, -1));
mLight->setDiffuseColour (Ogre::ColourValue (0.2, 0.2, 0.2));
mLightSource->setLight(light);
mRootNode->addChild(mLightSource);
}
void CSVRender::LightingNight::deactivate()
{
if (mLight)
{
mSceneManager->destroyLight (mLight);
mLight = 0;
}
if (mRootNode && mLightSource.get())
mRootNode->removeChild(mLightSource);
}
void CSVRender::LightingNight::setDefaultAmbient (const Ogre::ColourValue& colour)
osg::Vec4f CSVRender::LightingNight::getAmbientColour(osg::Vec4f *defaultAmbient)
{
mSceneManager->setAmbientLight (colour);
if (defaultAmbient)
return *defaultAmbient;
else
return osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f);
}

@ -3,28 +3,18 @@
#include "lighting.hpp"
namespace Ogre
{
class Light;
}
namespace CSVRender
{
class LightingNight : public Lighting
{
Ogre::SceneManager *mSceneManager;
Ogre::Light *mLight;
public:
LightingNight();
virtual void activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient = 0);
virtual void activate (osg::Group* rootNode);
virtual void deactivate();
virtual void setDefaultAmbient (const Ogre::ColourValue& colour);
virtual osg::Vec4f getAmbientColour(osg::Vec4f *defaultAmbient);
};
}

@ -1,463 +0,0 @@
#include "mousestate.hpp"
#include <OgreSceneNode.h>
#include <OgreSceneManager.h>
#include <OgreEntity.h>
#include <OgreMeshManager.h>
#include <QMouseEvent>
#include <QElapsedTimer>
#include <QObject>
#include "../../model/settings/usersettings.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/universalid.hpp"
#include "../world/physicssystem.hpp"
#include "elements.hpp"
#include "worldspacewidget.hpp"
namespace CSVRender
{
// mouse picking
// FIXME: need to virtualise mouse buttons
//
// State machine:
//
// [default] mousePressEvent->check if the mouse is pointing at an object
// if yes, create collision planes then go to [grab]
// else check for terrain
//
// [grab] mouseReleaseEvent->if same button and new obj, go to [edit]
// mouseMoveEvent->if same button, go to [drag]
// other mouse events or buttons, go back to [default] (i.e. like 'cancel')
//
// [drag] mouseReleaseEvent->if same button, place the object at the new
// location, update the document then go to [edit]
// mouseMoveEvent->update position to the user based on ray to the collision
// planes and render the object at the new location, but do not update
// the document yet
//
// [edit] TODO, probably fine positional adjustments or rotations; clone/delete?
//
//
// press press (obj)
// [default] --------> [grab] <-------------------- [edit]
// ^ (obj) | | ------> [drag] -----> ^
// | | | move ^ | release |
// | | | | | |
// | | | +-+ |
// | | | move |
// +----------------+ +--------------------------+
// release release
// (same obj) (new obj)
//
//
MouseState::MouseState(WorldspaceWidget *parent)
: mMouseState(Mouse_Default), mParent(parent), mPhysics(parent->mDocument.getPhysics())
, mSceneManager(parent->getSceneManager()), mOldPos(0,0), mCurrentObj(""), mGrabbedSceneNode("")
, mMouseEventTimer(0), mPlane(0), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3())
, mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f), mIdTableModel(0), mColIndexPosX(0)
, mColIndexPosY(0), mColIndexPosZ(0)
{
const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences();
mColIndexPosX = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionXPos);
mColIndexPosY = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionYPos);
mColIndexPosZ = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionZPos);
mIdTableModel = static_cast<CSMWorld::IdTable *>(
mParent->mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Reference));
mMouseEventTimer = new QElapsedTimer();
mMouseEventTimer->invalidate();
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
mPlane = new Ogre::Plane(planeRes.first, 0);
Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createPlane("mouse",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
*mPlane,
300000,300000, // FIXME: use far clip dist?
1,1, // segments
true, // normals
1, // numTexCoordSets
1,1, // uTile, vTile
planeRes.second // upVector
);
}
MouseState::~MouseState ()
{
delete mMouseEventTimer;
delete mPlane;
}
void MouseState::mouseMoveEvent (QMouseEvent *event)
{
switch(mMouseState)
{
case Mouse_Grab:
{
// check if min elapsed time to stop false detection of drag
if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms
break;
mMouseEventTimer->invalidate();
mMouseState = Mouse_Drag;
/* FALL_THROUGH */
}
case Mouse_Drag:
{
if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum?
{
mOldPos = event->pos();
// ray test against the plane to provide feedback to the user the
// relative movement of the object on the x-y plane
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane);
if(planeResult.first)
{
if(mGrabbedSceneNode != "")
{
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset;
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos);
mCurrentMousePos = planeResult.second;
mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos);
updateSceneWidgets();
}
}
}
break;
}
case Mouse_Edit:
case Mouse_Default:
{
break; // error event, ignore
}
/* NO_DEFAULT_CASE */
}
}
void MouseState::mousePressEvent (QMouseEvent *event)
{
switch(mMouseState)
{
case Mouse_Grab:
case Mouse_Drag:
{
break;
}
case Mouse_Edit:
case Mouse_Default:
{
if(event->buttons() & Qt::RightButton)
{
std::pair<std::string, Ogre::Vector3> result = objectUnderCursor(event->x(), event->y());
if(result.first == "")
break;
mGrabbedSceneNode = result.first;
// ray test agaist the plane to get a starting position of the
// mouse in relation to the object position
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
mPlane->redefine(planeRes.first, result.second);
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane);
if(planeResult.first)
{
mOrigMousePos = planeResult.second;
mCurrentMousePos = planeResult.second;
mOffset = 0.0f;
}
mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition();
mMouseEventTimer->start();
mMouseState = Mouse_Grab;
}
break;
}
/* NO_DEFAULT_CASE */
}
}
void MouseState::mouseReleaseEvent (QMouseEvent *event)
{
switch(mMouseState)
{
case Mouse_Grab:
{
std::pair<std::string, Ogre::Vector3> result = objectUnderCursor(event->x(), event->y());
if(result.first != "")
{
if(result.first == mCurrentObj)
{
// unselect object
mMouseState = Mouse_Default;
mCurrentObj = "";
}
else
{
// select object
mMouseState = Mouse_Edit;
mCurrentObj = result.first;
}
}
break;
}
case Mouse_Drag:
{
// final placement
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane);
if(planeResult.first)
{
if(mGrabbedSceneNode != "")
{
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos;
// use the saved scene node name since the physics model has not moved yet
std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode);
mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object"));
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x));
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
mIdTableModel->getModelIndex(referenceId, mColIndexPosY), pos.y));
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
mIdTableModel->getModelIndex(referenceId, mColIndexPosZ), pos.z));
mParent->mDocument.getUndoStack().endMacro();
// FIXME: highlight current object?
//mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work?
mCurrentObj = ""; // whether the object is selected
mMouseState = Mouse_Edit;
// reset states
mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event
mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space
mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space
mGrabbedSceneNode = ""; // id of the object
mOffset = 0.0f; // used for z-axis movement
mOldPos = QPoint(0, 0); // to calculate relative movement of mouse
}
}
break;
}
case Mouse_Edit:
case Mouse_Default:
{
// probably terrain, check
std::pair<std::string, Ogre::Vector3> result = terrainUnderCursor(event->x(), event->y());
if(result.first != "")
{
// FIXME: terrain editing goes here
}
break;
}
/* NO_DEFAULT_CASE */
}
mMouseEventTimer->invalidate();
}
void MouseState::mouseDoubleClickEvent (QMouseEvent *event)
{
event->ignore();
//mPhysics->toggleDebugRendering(mSceneManager);
//mParent->flagAsModified();
}
bool MouseState::wheelEvent (QWheelEvent *event)
{
switch(mMouseState)
{
case Mouse_Grab:
mMouseState = Mouse_Drag;
/* FALL_THROUGH */
case Mouse_Drag:
{
// move the object along the z axis during Mouse_Drag or Mouse_Grab
if (event->delta())
{
// seems positive is up and negative is down
mOffset += (event->delta()/1); // FIXME: arbitrary number, make config option?
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset;
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos);
mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos);
updateSceneWidgets();
}
break;
}
case Mouse_Edit:
case Mouse_Default:
{
return false;
}
/* NO_DEFAULT_CASE */
}
return true;
}
void MouseState::cancelDrag()
{
switch(mMouseState)
{
case Mouse_Grab:
case Mouse_Drag:
{
// cancel operation & return the object to the original position
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(mOrigObjPos);
// update all SceneWidgets and their SceneManagers
mPhysics->moveSceneNodes(mGrabbedSceneNode, mOrigObjPos);
updateSceneWidgets();
// reset states
mMouseState = Mouse_Default;
mCurrentMousePos = Ogre::Vector3();
mOrigMousePos = Ogre::Vector3();
mOrigObjPos = Ogre::Vector3();
mGrabbedSceneNode = "";
mCurrentObj = "";
mOldPos = QPoint(0, 0);
mMouseEventTimer->invalidate();
mOffset = 0.0f;
break;
}
case Mouse_Edit:
case Mouse_Default:
{
break;
}
/* NO_DEFAULT_CASE */
}
}
//plane Z, upvector Y, mOffset z : x-y plane, wheel up/down
//plane Y, upvector X, mOffset y : y-z plane, wheel left/right
//plane X, upvector Y, mOffset x : x-z plane, wheel closer/further
std::pair<Ogre::Vector3, Ogre::Vector3> MouseState::planeAxis()
{
const bool screenCoord = true;
Ogre::Vector3 dir = getCamera()->getDerivedDirection();
QString wheelDir = "Closer/Further";
if(wheelDir == "Left/Right")
{
if(screenCoord)
return std::make_pair(getCamera()->getDerivedRight(), getCamera()->getDerivedUp());
else
return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_Z);
}
else if(wheelDir == "Up/Down")
{
if(screenCoord)
return std::make_pair(getCamera()->getDerivedUp(), Ogre::Vector3(-dir.x, -dir.y, -dir.z));
else
return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_X);
}
else
{
if(screenCoord)
return std::make_pair(Ogre::Vector3(-dir.x, -dir.y, -dir.z), getCamera()->getDerivedRight());
else
return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y);
}
}
std::pair<bool, Ogre::Vector3> MouseState::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane)
{
// using a really small value seems to mess up with the projections
float nearClipDistance = getCamera()->getNearClipDistance(); // save existing
getCamera()->setNearClipDistance(10.0f); // arbitrary number
Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay(
(float) pos.x() / getViewport()->getActualWidth(),
(float) pos.y() / getViewport()->getActualHeight());
getCamera()->setNearClipDistance(nearClipDistance); // restore
std::pair<bool, float> planeResult = mouseRay.intersects(plane);
if(planeResult.first)
return std::make_pair(true, mouseRay.getPoint(planeResult.second));
else
return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small
}
std::pair<std::string, Ogre::Vector3> MouseState::terrainUnderCursor(const int mouseX, const int mouseY)
{
if(!getViewport())
return std::make_pair("", Ogre::Vector3());
float x = (float) mouseX / getViewport()->getActualWidth();
float y = (float) mouseY / getViewport()->getActualHeight();
std::pair<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera());
if(result.first != "")
{
// FIXME: is there a better way to distinguish terrain from objects?
QString name = QString(result.first.c_str());
if(name.contains(QRegExp("^HeightField")))
{
return result;
}
}
return std::make_pair("", Ogre::Vector3());
}
std::pair<std::string, Ogre::Vector3> MouseState::objectUnderCursor(const int mouseX, const int mouseY)
{
if(!getViewport())
return std::make_pair("", Ogre::Vector3());
float x = (float) mouseX / getViewport()->getActualWidth();
float y = (float) mouseY / getViewport()->getActualHeight();
std::pair<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera());
if(result.first != "")
{
// NOTE: anything not terrain is assumed to be an object
QString name = QString(result.first.c_str());
if(!name.contains(QRegExp("^HeightField")))
{
uint32_t visibilityMask = getViewport()->getVisibilityMask();
bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference);
if(!ignoreObjects && mSceneManager->hasSceneNode(result.first))
{
return result;
}
}
}
return std::make_pair("", Ogre::Vector3());
}
void MouseState::updateSceneWidgets()
{
std::map<Ogre::SceneManager*, CSVRender::SceneWidget *> sceneWidgets = mPhysics->sceneWidgets();
std::map<Ogre::SceneManager*, CSVRender::SceneWidget *>::iterator iter = sceneWidgets.begin();
for(; iter != sceneWidgets.end(); ++iter)
{
(*iter).second->updateScene();
}
}
Ogre::Camera *MouseState::getCamera()
{
return mParent->getCamera();
}
Ogre::Viewport *MouseState::getViewport()
{
return mParent->getCamera()->getViewport();
}
}

@ -1,91 +0,0 @@
#ifndef OPENCS_VIEW_MOUSESTATE_H
#define OPENCS_VIEW_MOUSESTATE_H
#include <map>
#include <boost/shared_ptr.hpp>
#include <QPoint>
#include <OgreVector3.h>
class QElapsedTimer;
class QMouseEvent;
class QWheelEvent;
namespace Ogre
{
class Plane;
class SceneManager;
class Camera;
class Viewport;
}
namespace CSVWorld
{
class PhysicsSystem;
}
namespace CSMWorld
{
class IdTable;
}
namespace CSVRender
{
class WorldspaceWidget;
class MouseState
{
enum MouseStates
{
Mouse_Grab,
Mouse_Drag,
Mouse_Edit,
Mouse_Default
};
MouseStates mMouseState;
WorldspaceWidget *mParent;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
Ogre::SceneManager *mSceneManager; // local copy
QPoint mOldPos;
std::string mCurrentObj;
std::string mGrabbedSceneNode;
QElapsedTimer *mMouseEventTimer;
Ogre::Plane *mPlane;
Ogre::Vector3 mOrigObjPos;
Ogre::Vector3 mOrigMousePos;
Ogre::Vector3 mCurrentMousePos;
float mOffset;
CSMWorld::IdTable *mIdTableModel;
int mColIndexPosX;
int mColIndexPosY;
int mColIndexPosZ;
public:
MouseState(WorldspaceWidget *parent);
~MouseState();
void mouseMoveEvent (QMouseEvent *event);
void mousePressEvent (QMouseEvent *event);
void mouseReleaseEvent (QMouseEvent *event);
void mouseDoubleClickEvent (QMouseEvent *event);
bool wheelEvent (QWheelEvent *event);
void cancelDrag();
private:
std::pair<bool, Ogre::Vector3> mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane);
std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY);
std::pair<std::string, Ogre::Vector3> objectUnderCursor(const int mouseX, const int mouseY);
std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis();
void updateSceneWidgets();
Ogre::Camera *getCamera(); // friend access
Ogre::Viewport *getViewport(); // friend access
};
}
#endif // OPENCS_VIEW_MOUSESTATE_H

@ -1,24 +0,0 @@
#include "navigation.hpp"
float CSVRender::Navigation::getFactor (bool mouse) const
{
float factor = mFastModeFactor;
if (mouse)
factor /= 2; /// \todo make this configurable
return factor;
}
CSVRender::Navigation::Navigation()
: mFastModeFactor(1)
{
}
CSVRender::Navigation::~Navigation() {}
void CSVRender::Navigation::setFastModeFactor (float factor)
{
mFastModeFactor = factor;
}

@ -1,47 +0,0 @@
#ifndef OPENCS_VIEW_NAVIGATION_H
#define OPENCS_VIEW_NAVIGATION_H
class QPoint;
namespace Ogre
{
class Camera;
}
namespace CSVRender
{
class Navigation
{
float mFastModeFactor;
protected:
float getFactor (bool mouse) const;
public:
Navigation();
virtual ~Navigation();
void setFastModeFactor (float factor);
///< Set currently applying fast mode factor.
virtual bool activate (Ogre::Camera *camera) = 0;
///< \return Update required?
virtual bool wheelMoved (int delta) = 0;
///< \return Update required?
virtual bool mouseMoved (const QPoint& delta, int mode) = 0;
///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1
/// \return Update required?
virtual bool handleMovementKeys (int vertical, int horizontal) = 0;
///< \return Update required?
virtual bool handleRollKeys (int delta) = 0;
///< \return Update required?
};
}
#endif

@ -1,86 +0,0 @@
#include "navigation1st.hpp"
#include <OgreCamera.h>
#include <QPoint>
CSVRender::Navigation1st::Navigation1st() : mCamera (0) {}
bool CSVRender::Navigation1st::activate (Ogre::Camera *camera)
{
mCamera = camera;
mCamera->setFixedYawAxis (true, Ogre::Vector3::UNIT_Z);
Ogre::Radian pitch = mCamera->getOrientation().getPitch();
Ogre::Radian limit (Ogre::Math::PI/2-0.5);
if (pitch>limit)
mCamera->pitch (-(pitch-limit));
else if (pitch<-limit)
mCamera->pitch (pitch-limit);
return true;
}
bool CSVRender::Navigation1st::wheelMoved (int delta)
{
mCamera->move (getFactor (true) * mCamera->getDirection() * delta);
return true;
}
bool CSVRender::Navigation1st::mouseMoved (const QPoint& delta, int mode)
{
if (mode==0)
{
// turn camera
if (delta.x())
mCamera->yaw (Ogre::Degree (getFactor (true) * delta.x()));
if (delta.y())
{
Ogre::Radian oldPitch = mCamera->getOrientation().getPitch();
float deltaPitch = getFactor (true) * delta.y();
Ogre::Radian newPitch = oldPitch + Ogre::Degree (deltaPitch);
if ((deltaPitch>0 && newPitch<Ogre::Radian(Ogre::Math::PI-0.5)) ||
(deltaPitch<0 && newPitch>Ogre::Radian(0.5)))
{
mCamera->pitch (Ogre::Degree (deltaPitch));
}
}
return true;
}
else if (mode==1)
{
// pan camera
if (delta.x())
mCamera->move (getFactor (true) * mCamera->getDerivedRight() * delta.x());
if (delta.y())
mCamera->move (getFactor (true) * -mCamera->getDerivedUp() * delta.y());
return true;
}
return false;
}
bool CSVRender::Navigation1st::handleMovementKeys (int vertical, int horizontal)
{
if (vertical)
mCamera->move (getFactor (false) * mCamera->getDirection() * vertical);
if (horizontal)
mCamera->move (getFactor (true) * mCamera->getDerivedRight() * horizontal);
return true;
}
bool CSVRender::Navigation1st::handleRollKeys (int delta)
{
// we don't roll this way in 1st person mode
return false;
}

@ -1,35 +0,0 @@
#ifndef OPENCS_VIEW_NAVIGATION1ST_H
#define OPENCS_VIEW_NAVIGATION1ST_H
#include "navigation.hpp"
namespace CSVRender
{
/// \brief First person-like camera controls
class Navigation1st : public Navigation
{
Ogre::Camera *mCamera;
public:
Navigation1st();
virtual bool activate (Ogre::Camera *camera);
///< \return Update required?
virtual bool wheelMoved (int delta);
///< \return Update required?
virtual bool mouseMoved (const QPoint& delta, int mode);
///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1
/// \return Update required?
virtual bool handleMovementKeys (int vertical, int horizontal);
///< \return Update required?
virtual bool handleRollKeys (int delta);
///< \return Update required?
};
}
#endif

@ -1,66 +0,0 @@
#include "navigationfree.hpp"
#include <OgreCamera.h>
#include <QPoint>
CSVRender::NavigationFree::NavigationFree() : mCamera (0) {}
bool CSVRender::NavigationFree::activate (Ogre::Camera *camera)
{
mCamera = camera;
mCamera->setFixedYawAxis (false);
return false;
}
bool CSVRender::NavigationFree::wheelMoved (int delta)
{
mCamera->move (getFactor (true) * mCamera->getDirection() * delta);
return true;
}
bool CSVRender::NavigationFree::mouseMoved (const QPoint& delta, int mode)
{
if (mode==0)
{
// turn camera
if (delta.x())
mCamera->yaw (Ogre::Degree (getFactor (true) * delta.x()));
if (delta.y())
mCamera->pitch (Ogre::Degree (getFactor (true) * delta.y()));
return true;
}
else if (mode==1)
{
// pan camera
if (delta.x())
mCamera->move (getFactor (true) * mCamera->getDerivedRight() * delta.x());
if (delta.y())
mCamera->move (getFactor (true) * -mCamera->getDerivedUp() * delta.y());
return true;
}
return false;
}
bool CSVRender::NavigationFree::handleMovementKeys (int vertical, int horizontal)
{
if (vertical)
mCamera->move (getFactor (false) * mCamera->getDerivedUp() * vertical);
if (horizontal)
mCamera->move (getFactor (true) * mCamera->getDerivedRight() * horizontal);
return true;
}
bool CSVRender::NavigationFree::handleRollKeys (int delta)
{
mCamera->roll (Ogre::Degree (getFactor (false) * delta));
return true;
}

@ -1,35 +0,0 @@
#ifndef OPENCS_VIEW_NAVIGATIONFREE_H
#define OPENCS_VIEW_NAVIGATIONFREE_H
#include "navigation.hpp"
namespace CSVRender
{
/// \brief Free camera controls
class NavigationFree : public Navigation
{
Ogre::Camera *mCamera;
public:
NavigationFree();
virtual bool activate (Ogre::Camera *camera);
///< \return Update required?
virtual bool wheelMoved (int delta);
///< \return Update required?
virtual bool mouseMoved (const QPoint& delta, int mode);
///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1
/// \return Update required?
virtual bool handleMovementKeys (int vertical, int horizontal);
///< \return Update required?
virtual bool handleRollKeys (int delta);
///< \return Update required?
};
}
#endif

@ -1,100 +0,0 @@
#include "navigationorbit.hpp"
#include <OgreCamera.h>
#include <QPoint>
void CSVRender::NavigationOrbit::rotateCamera (const Ogre::Vector3& diff)
{
Ogre::Vector3 pos = mCamera->getPosition();
float distance = (pos-mCentre).length();
Ogre::Vector3 direction = (pos+diff)-mCentre;
direction.normalise();
mCamera->setPosition (mCentre + direction*distance);
mCamera->lookAt (mCentre);
}
CSVRender::NavigationOrbit::NavigationOrbit() : mCamera (0), mCentre (0, 0, 0), mDistance (100)
{}
bool CSVRender::NavigationOrbit::activate (Ogre::Camera *camera)
{
mCamera = camera;
mCamera->setFixedYawAxis (false);
if ((mCamera->getPosition()-mCentre).length()<mDistance)
{
// move camera out of the centre area
Ogre::Vector3 direction = mCentre-mCamera->getPosition();
direction.normalise();
if (direction.length()==0)
direction = Ogre::Vector3 (1, 0, 0);
mCamera->setPosition (mCentre - direction * mDistance);
}
mCamera->lookAt (mCentre);
return true;
}
bool CSVRender::NavigationOrbit::wheelMoved (int delta)
{
Ogre::Vector3 diff = getFactor (true) * mCamera->getDirection() * delta;
Ogre::Vector3 pos = mCamera->getPosition();
if (delta>0 && diff.length()>=(pos-mCentre).length()-mDistance)
{
pos = mCentre-(mCamera->getDirection() * mDistance);
}
else
{
pos += diff;
}
mCamera->setPosition (pos);
return true;
}
bool CSVRender::NavigationOrbit::mouseMoved (const QPoint& delta, int mode)
{
Ogre::Vector3 diff =
getFactor (true) * -mCamera->getDerivedRight() * delta.x()
+ getFactor (true) * mCamera->getDerivedUp() * delta.y();
if (mode==0)
{
rotateCamera (diff);
return true;
}
else if (mode==1)
{
mCamera->move (diff);
mCentre += diff;
return true;
}
return false;
}
bool CSVRender::NavigationOrbit::handleMovementKeys (int vertical, int horizontal)
{
rotateCamera (
- getFactor (false) * -mCamera->getDerivedRight() * horizontal
+ getFactor (false) * mCamera->getDerivedUp() * vertical);
return true;
}
bool CSVRender::NavigationOrbit::handleRollKeys (int delta)
{
mCamera->roll (Ogre::Degree (getFactor (false) * delta));
return true;
}

@ -1,42 +0,0 @@
#ifndef OPENCS_VIEW_NAVIGATIONORBIT_H
#define OPENCS_VIEW_NAVIGATIONORBIT_H
#include "navigation.hpp"
#include <OgreVector3.h>
namespace CSVRender
{
/// \brief Orbiting camera controls
class NavigationOrbit : public Navigation
{
Ogre::Camera *mCamera;
Ogre::Vector3 mCentre;
int mDistance;
void rotateCamera (const Ogre::Vector3& diff);
///< Rotate camera around centre.
public:
NavigationOrbit();
virtual bool activate (Ogre::Camera *camera);
///< \return Update required?
virtual bool wheelMoved (int delta);
///< \return Update required?
virtual bool mouseMoved (const QPoint& delta, int mode);
///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1
/// \return Update required?
virtual bool handleMovementKeys (int vertical, int horizontal);
///< \return Update required?
virtual bool handleRollKeys (int delta);
///< \return Update required?
};
}
#endif

@ -1,53 +1,50 @@
#include "object.hpp"
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <OgreEntity.h>
#include <stdexcept>
#include <osg/Group>
#include <osg/PositionAttitudeTransform>
#include <osg/ShapeDrawable>
#include <osg/Shape>
#include <osg/Geode>
#include "../../model/world/data.hpp"
#include "../../model/world/ref.hpp"
#include "../../model/world/refidcollection.hpp"
#include "../world/physicssystem.hpp"
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/clone.hpp>
#include "elements.hpp"
void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node)
namespace
{
for (Ogre::SceneNode::ObjectIterator iter = node->getAttachedObjectIterator();
iter.hasMoreElements(); )
osg::ref_ptr<osg::Geode> createErrorCube()
{
Ogre::MovableObject* object = dynamic_cast<Ogre::MovableObject*> (iter.getNext());
node->getCreator()->destroyMovableObject (object);
osg::ref_ptr<osg::Box> shape(new osg::Box(osg::Vec3f(0,0,0), 50.f));
osg::ref_ptr<osg::ShapeDrawable> shapedrawable(new osg::ShapeDrawable);
shapedrawable->setShape(shape);
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(shapedrawable);
return geode;
}
for (Ogre::SceneNode::ChildNodeIterator iter = node->getChildIterator();
iter.hasMoreElements(); )
{
Ogre::SceneNode* childNode = dynamic_cast<Ogre::SceneNode*> (iter.getNext());
clearSceneNode (childNode);
node->getCreator()->destroySceneNode (childNode);
}
}
void CSVRender::Object::clear()
{
mObject.setNull();
if (mBase)
clearSceneNode (mBase);
}
void CSVRender::Object::update()
{
if(!mObject.isNull())
mPhysics->removePhysicsObject(mBase->getName());
clear();
std::string model;
int error = 0; // 1 referemceanöe does not exist, 2 referenceable does not specify a mesh
int error = 0; // 1 referenceable does not exist, 2 referenceable does not specify a mesh
const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables();
@ -67,39 +64,29 @@ void CSVRender::Object::update()
error = 2;
}
mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
if (error)
{
Ogre::Entity* entity = mBase->getCreator()->createEntity (Ogre::SceneManager::PT_CUBE);
entity->setMaterialName("BaseWhite"); /// \todo adjust material according to error
entity->setVisibilityFlags (Element_Reference);
mBase->attachObject (entity);
mBaseNode->addChild(createErrorCube());
}
else
{
mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model);
mObject->setVisibilityFlags (Element_Reference);
if (mPhysics && !mReferenceId.empty())
try
{
const CSMWorld::CellRef& reference = getReference();
// position
Ogre::Vector3 position;
if (!mForceBaseToZero)
position = Ogre::Vector3(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]);
std::string path = "meshes\\" + model;
// orientation
Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X);
Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.rot[1]), Ogre::Vector3::UNIT_Y);
Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z);
mPhysics->addObject("meshes\\" + model, mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr);
mResourceSystem->getSceneManager()->createInstance(path, mBaseNode);
}
catch (std::exception& e)
{
// TODO: use error marker mesh
std::cerr << e.what() << std::endl;
}
}
}
void CSVRender::Object::adjust()
void CSVRender::Object::adjustTransform()
{
if (mReferenceId.empty())
return;
@ -107,21 +94,15 @@ void CSVRender::Object::adjust()
const CSMWorld::CellRef& reference = getReference();
// position
if (!mForceBaseToZero)
mBase->setPosition (Ogre::Vector3 (
reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]));
mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]));
// orientation
Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X);
Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.rot[1]), Ogre::Vector3::UNIT_Y);
Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z);
mBase->setOrientation (xr*yr*zr);
osg::Quat xr (-reference.mPos.rot[0], osg::Vec3f(1,0,0));
osg::Quat yr (-reference.mPos.rot[1], osg::Vec3f(0,1,0));
osg::Quat zr (-reference.mPos.rot[2], osg::Vec3f(0,0,1));
mBaseNode->setAttitude(zr*yr*xr);
// scale
mBase->setScale (reference.mScale, reference.mScale, reference.mScale);
mBaseNode->setScale(osg::Vec3(reference.mScale, reference.mScale, reference.mScale));
}
const CSMWorld::CellRef& CSVRender::Object::getReference() const
@ -132,12 +113,15 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const
return mData.getReferences().getRecord (mReferenceId).get();
}
CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode,
const std::string& id, bool referenceable, boost::shared_ptr<CSVWorld::PhysicsSystem> physics,
bool forceBaseToZero)
: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics)
CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
const std::string& id, bool referenceable, bool forceBaseToZero)
: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem()), mForceBaseToZero (forceBaseToZero)
{
mBase = cellNode->createChildSceneNode();
mBaseNode = new osg::PositionAttitudeTransform;
parentNode->addChild(mBaseNode);
// 0x1 reserved for separating cull and update visitors
mBaseNode->setNodeMask(Element_Reference<<1);
if (referenceable)
{
@ -149,21 +133,15 @@ CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode
mReferenceableId = getReference().mRefID;
}
adjustTransform();
update();
adjust();
}
CSVRender::Object::~Object()
{
clear();
if (mBase)
{
if(mPhysics) // preview may not have physics enabled
mPhysics->removeObject(mBase->getName());
mBase->getCreator()->destroySceneNode (mBase);
}
mParentNode->removeChild(mBaseNode);
}
bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft,
@ -175,8 +153,8 @@ bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft,
if (index!=-1 && index>=topLeft.row() && index<=bottomRight.row())
{
adjustTransform();
update();
adjust();
return true;
}
@ -195,8 +173,8 @@ bool CSVRender::Object::referenceableAboutToBeRemoved (const QModelIndex& parent
// Deletion of referenceable-type objects is handled outside of Object.
if (!mReferenceId.empty())
{
adjustTransform();
update();
adjust();
return true;
}
}
@ -219,6 +197,8 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft,
int columnIndex =
references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId);
adjustTransform();
if (columnIndex>=topLeft.column() && columnIndex<=bottomRight.row())
{
mReferenceableId =
@ -227,8 +207,6 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft,
update();
}
adjust();
return true;
}

@ -1,28 +1,30 @@
#ifndef OPENCS_VIEW_OBJECT_H
#define OPENCS_VIEW_OBJECT_H
#include <string>
#include <boost/shared_ptr.hpp>
#ifndef Q_MOC_RUN
#include <components/nifogre/ogrenifloader.hpp>
#endif
#include <osg/ref_ptr>
class QModelIndex;
namespace Ogre
namespace osg
{
class SceneNode;
class PositionAttitudeTransform;
class Group;
}
namespace CSMWorld
namespace Resource
{
class Data;
struct CellRef;
class ResourceSystem;
}
namespace CSVWorld
namespace CSMWorld
{
class PhysicsSystem;
class Data;
struct CellRef;
}
namespace CSVRender
@ -32,10 +34,10 @@ namespace CSVRender
const CSMWorld::Data& mData;
std::string mReferenceId;
std::string mReferenceableId;
Ogre::SceneNode *mBase;
NifOgre::ObjectScenePtr mObject;
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
osg::Group* mParentNode;
Resource::ResourceSystem* mResourceSystem;
bool mForceBaseToZero;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
/// Not implemented
Object (const Object&);
@ -43,26 +45,23 @@ namespace CSVRender
/// Not implemented
Object& operator= (const Object&);
/// Destroy all scene nodes and movable objects attached to node.
static void clearSceneNode (Ogre::SceneNode *node);
/// Remove object from node (includes deleting)
void clear();
/// Update model
/// @note Make sure adjustTransform() was called first so world space particles get positioned correctly
void update();
/// Adjust position, orientation and scale
void adjust();
void adjustTransform();
/// Throws an exception if *this was constructed with referenceable
const CSMWorld::CellRef& getReference() const;
public:
Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode,
Object (CSMWorld::Data& data, osg::Group *cellNode,
const std::string& id, bool referenceable,
boost::shared_ptr<CSVWorld::PhysicsSystem> physics = boost::shared_ptr<CSVWorld::PhysicsSystem> (),
bool forceBaseToZero = false);
/// \param forceBaseToZero If this is a reference ignore the coordinates and place
/// it at 0, 0, 0 instead.

@ -1,52 +0,0 @@
#include "overlaymask.hpp"
#include <OgreOverlayManager.h>
#include <OgreOverlayContainer.h>
#include "textoverlay.hpp"
#include "../../model/world/cellcoordinates.hpp"
namespace CSVRender
{
// ideas from http://www.ogre3d.org/forums/viewtopic.php?f=5&t=44828#p486334
OverlayMask::OverlayMask(std::map<CSMWorld::CellCoordinates, TextOverlay *> &overlays, Ogre::Viewport* viewport)
: mTextOverlays(overlays), mViewport(viewport)
{
}
OverlayMask::~OverlayMask()
{
}
void OverlayMask::setViewport(Ogre::Viewport *viewport)
{
mViewport = viewport;
}
void OverlayMask::preViewportUpdate(const Ogre::RenderTargetViewportEvent &event)
{
if(event.source == mViewport)
{
Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton();
for(Ogre::OverlayManager::OverlayMapIterator iter = overlayMgr.getOverlayIterator();
iter.hasMoreElements();)
{
Ogre::Overlay* item = iter.getNext();
for(Ogre::Overlay::Overlay2DElementsIterator it = item->get2DElementsIterator();
it.hasMoreElements();)
{
Ogre::OverlayContainer* container = it.getNext();
if(container) container->hide();
}
}
std::map<CSMWorld::CellCoordinates, TextOverlay *>::iterator it = mTextOverlays.begin();
for(; it != mTextOverlays.end(); ++it)
{
it->second->show(true);
}
}
}
}

@ -1,42 +0,0 @@
#ifndef OPENCS_VIEW_OVERLAYMASK_H
#define OPENCS_VIEW_OVERLAYMASK_H
#include <OgreRenderTargetListener.h>
namespace Ogre
{
class Viewport;
class RendertargetViewportEvent;
}
namespace CSMWorld
{
class CellCoordinates;
}
namespace CSVRender
{
class TextOverlay;
class OverlayMask : public Ogre::RenderTargetListener
{
std::map<CSMWorld::CellCoordinates, TextOverlay *> &mTextOverlays;
Ogre::Viewport* mViewport;
public:
OverlayMask(std::map<CSMWorld::CellCoordinates, TextOverlay *> &overlays,
Ogre::Viewport* viewport);
virtual ~OverlayMask();
void setViewport(Ogre::Viewport *viewport);
protected:
virtual void preViewportUpdate(const Ogre::RenderTargetViewportEvent &event);
};
}
#endif // OPENCS_VIEW_OVERLAYMASK_H

@ -1,34 +0,0 @@
#include "overlaysystem.hpp"
#include <cassert>
#include <OgreOverlaySystem.h>
namespace CSVRender
{
OverlaySystem *OverlaySystem::mOverlaySystemInstance = 0;
OverlaySystem::OverlaySystem()
{
assert(!mOverlaySystemInstance);
mOverlaySystemInstance = this;
mOverlaySystem = new Ogre::OverlaySystem();
}
OverlaySystem::~OverlaySystem()
{
delete mOverlaySystem;
}
OverlaySystem &OverlaySystem::instance()
{
assert(mOverlaySystemInstance);
return *mOverlaySystemInstance;
}
Ogre::OverlaySystem *OverlaySystem::get()
{
return mOverlaySystem;
}
}

@ -1,26 +0,0 @@
#ifndef OPENCS_VIEW_OVERLAYSYSTEM_H
#define OPENCS_VIEW_OVERLAYSYSTEM_H
namespace Ogre
{
class OverlaySystem;
}
namespace CSVRender
{
class OverlaySystem
{
Ogre::OverlaySystem *mOverlaySystem;
static OverlaySystem *mOverlaySystemInstance;
public:
OverlaySystem();
~OverlaySystem();
static OverlaySystem &instance();
Ogre::OverlaySystem *get();
};
}
#endif // OPENCS_VIEW_OVERLAYSYSTEM_H

@ -5,17 +5,9 @@
#include <QMouseEvent>
#include <OgreCamera.h>
#include <OgreSceneManager.h>
#include <OgreManualObject.h>
#include <OgreOverlayContainer.h>
#include <OgreOverlayManager.h>
#include <OgreRoot.h>
#include <OgreSceneQuery.h>
#include <osgGA/TrackballManipulator>
#include <components/esm/loadland.hpp>
#include "textoverlay.hpp"
#include "overlaymask.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/idtable.hpp"
@ -30,7 +22,6 @@
bool CSVRender::PagedWorldspaceWidget::adjustCells()
{
bool modified = false;
bool setCamera = false;
const CSMWorld::IdCollection<CSMWorld::Cell>& cells = mDocument.getData().getCells();
@ -45,17 +36,6 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
if (!mSelection.has (iter->first) || index==-1 ||
cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted)
{
// delete overlays
std::map<CSMWorld::CellCoordinates, TextOverlay *>::iterator itOverlay = mTextOverlays.find(iter->first);
if(itOverlay != mTextOverlays.end())
{
delete itOverlay->second;
mTextOverlays.erase(itOverlay);
}
// destroy manual objects
getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace));
delete iter->second;
mCells.erase (iter++);
@ -65,43 +45,16 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
{
// check if name or region field has changed
// FIXME: config setting
std::string name = cells.getRecord(index).get().mName;
std::string region = cells.getRecord(index).get().mRegion;
std::map<CSMWorld::CellCoordinates, TextOverlay *>::iterator it = mTextOverlays.find(iter->first);
if(it != mTextOverlays.end())
{
if(it->second->getDesc() != "") // previously had name
{
if(name != it->second->getDesc()) // new name
{
if(name != "")
it->second->setDesc(name);
else // name deleted, use region
it->second->setDesc(region);
it->second->update();
}
}
else if(name != "") // name added
{
it->second->setDesc(name);
it->second->update();
}
else if(region != it->second->getDesc()) // new region
{
it->second->setDesc(region);
it->second->update();
}
modified = true;
}
//std::string name = cells.getRecord(index).get().mName;
//std::string region = cells.getRecord(index).get().mRegion;
// cell marker update goes here
++iter;
}
}
}
if (mCells.begin()==mCells.end())
setCamera = true;
// add
for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end();
++iter)
@ -111,106 +64,18 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted &&
mCells.find (*iter)==mCells.end())
{
Cell *cell = new Cell (mDocument.getData(), getSceneManager(),
iter->getId (mWorldspace), mDocument.getPhysics());
Cell *cell = new Cell (mDocument.getData(), mRootNode,
iter->getId (mWorldspace));
mCells.insert (std::make_pair (*iter, cell));
float height = cell->getTerrainHeightAt(Ogre::Vector3(
ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2,
ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2,
0));
if (setCamera)
{
setCamera = false;
getCamera()->setPosition (
ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2,
ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2,
height);
// better camera position at the start
getCamera()->move(getCamera()->getDirection() * -6000); // FIXME: config setting
}
Ogre::ManualObject* manual =
getSceneManager()->createManualObject("manual" + iter->getId(mWorldspace));
manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST);
// define start and end point (x, y, z)
manual-> position(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2,
ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2,
height);
manual-> position(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2,
ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2,
height+200); // FIXME: config setting
manual->end();
manual->setBoundingBox(Ogre::AxisAlignedBox(
ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2,
ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2,
height,
ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2,
ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2,
height+200));
getSceneManager()->getRootSceneNode()->createChildSceneNode()->attachObject(manual);
manual->setVisible(false);
CSVRender::TextOverlay *textDisp =
new CSVRender::TextOverlay(manual, getCamera(), iter->getId(mWorldspace));
textDisp->enable(true);
textDisp->setCaption(iter->getId(mWorldspace));
std::string desc = cells.getRecord(index).get().mName;
if(desc == "") desc = cells.getRecord(index).get().mRegion;
textDisp->setDesc(desc); // FIXME: config setting
textDisp->update();
mTextOverlays.insert(std::make_pair(*iter, textDisp));
if(!mOverlayMask)
{
mOverlayMask = new OverlayMask(mTextOverlays, getViewport());
addRenderTargetListener(mOverlayMask);
}
modified = true;
}
}
return modified;
}
void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event)
{
if(event->button() == Qt::RightButton)
{
std::map<CSMWorld::CellCoordinates, TextOverlay *>::iterator iter = mTextOverlays.begin();
for(; iter != mTextOverlays.end(); ++iter)
{
if(mDisplayCellCoord &&
iter->second->isEnabled() && iter->second->container().contains(event->x(), event->y()))
{
return;
}
}
}
WorldspaceWidget::mousePressEvent(event);
}
void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event)
{
if(event->button() == Qt::RightButton)
{
std::map<CSMWorld::CellCoordinates, TextOverlay *>::iterator iter = mTextOverlays.begin();
for(; iter != mTextOverlays.end(); ++iter)
{
if(mDisplayCellCoord &&
iter->second->isEnabled() && iter->second->container().contains(event->x(), event->y()))
{
std::cout << "clicked: " << iter->second->getCaption() << std::endl;
return;
}
}
}
WorldspaceWidget::mouseReleaseEvent(event);
}
if (modified)
mView->setCameraManipulator(new osgGA::TrackballManipulator);
void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event)
{
WorldspaceWidget::mouseDoubleClickEvent(event);
return modified;
}
void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons (
@ -241,28 +106,6 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
"terrain-move");
}
void CSVRender::PagedWorldspaceWidget::updateOverlay()
{
if(getCamera()->getViewport())
{
if((uint32_t)getCamera()->getViewport()->getVisibilityMask()
& (uint32_t)CSVRender::Element_CellMarker)
mDisplayCellCoord = true;
else
mDisplayCellCoord = false;
}
if(!mTextOverlays.empty())
{
std::map<CSMWorld::CellCoordinates, TextOverlay *>::iterator it = mTextOverlays.begin();
for(; it != mTextOverlays.end(); ++it)
{
it->second->enable(mDisplayCellCoord);
it->second->update();
}
}
}
void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
@ -328,13 +171,12 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
{
Ogre::Vector3 position = getCamera()->getPosition();
osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans();
std::ostringstream stream;
stream
<< "player->position "
<< position.x << ", " << position.y << ", " << position.z
<< position.x() << ", " << position.y() << ", " << position.z()
<< ", 0";
return stream.str();
@ -342,7 +184,7 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
: WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"),
mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL)
mControlElements(NULL), mDisplayCellCoord(true)
{
QAbstractItemModel *cells =
document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells);
@ -361,20 +203,6 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget()
iter!=mCells.end(); ++iter)
{
delete iter->second;
getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace));
}
for (std::map<CSMWorld::CellCoordinates, TextOverlay *>::iterator iter (mTextOverlays.begin());
iter != mTextOverlays.end(); ++iter)
{
delete iter->second;
}
if(mOverlayMask)
{
removeRenderTargetListener(mOverlayMask);
delete mOverlayMask;
}
}

@ -28,8 +28,6 @@ namespace CSVRender
std::string mWorldspace;
CSVWidget::SceneToolToggle *mControlElements;
bool mDisplayCellCoord;
std::map<CSMWorld::CellCoordinates, TextOverlay *> mTextOverlays;
OverlayMask *mOverlayMask;
private:
@ -87,14 +85,6 @@ namespace CSVRender
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
virtual void updateOverlay();
virtual void mousePressEvent (QMouseEvent *event);
virtual void mouseReleaseEvent (QMouseEvent *event);
virtual void mouseDoubleClickEvent (QMouseEvent *event);
signals:
void cellSelectionChanged (const CSMWorld::CellSelection& selection);

@ -1,18 +1,16 @@
#include "previewwidget.hpp"
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <osgGA/TrackballManipulator>
#include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp"
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
const std::string& id, bool referenceable, QWidget *parent)
: SceneWidget (parent), mData (data),
mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, boost::shared_ptr<CSVWorld::PhysicsSystem>(), true)
: SceneWidget (data.getResourceSystem()->getSceneManager(), parent), mData (data), mObject(data, mRootNode, id, referenceable)
{
setNavigation (&mOrbit);
mView->setCameraManipulator(new osgGA::TrackballManipulator);
QAbstractItemModel *referenceables =
mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables);

@ -3,11 +3,15 @@
#include "scenewidget.hpp"
#include "navigationorbit.hpp"
#include "object.hpp"
class QModelIndex;
namespace VFS
{
class Manager;
}
namespace CSMWorld
{
class Data;
@ -20,8 +24,7 @@ namespace CSVRender
Q_OBJECT
CSMWorld::Data& mData;
CSVRender::NavigationOrbit mOrbit;
Object mObject;
CSVRender::Object mObject;
public:

@ -4,467 +4,218 @@
#include <QResizeEvent>
#include <QTimer>
#include <QShortcut>
#include <QLayout>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <OgreEntity.h>
#include <OgreCamera.h>
#include <OgreSceneNode.h>
#include <OgreViewport.h>
#include <OgreOverlaySystem.h>
#include <osgQt/GraphicsWindowQt>
#include <osg/GraphicsContext>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osg/LightModel>
#include <components/resource/scenemanager.hpp>
#include "../widget/scenetoolmode.hpp"
#include "../../model/settings/usersettings.hpp"
#include "navigation.hpp"
#include "lighting.hpp"
#include "overlaysystem.hpp"
namespace CSVRender
{
SceneWidget::SceneWidget(QWidget *parent)
: QWidget(parent)
, mCamera(NULL)
, mSceneMgr(NULL)
, mWindow(NULL)
, mViewport(NULL)
, mNavigation (0), mLighting (0), mUpdate (false), mKeyForward (false)
, mKeyBackward (false), mKeyLeft (false), mKeyRight (false)
, mKeyRollLeft (false), mKeyRollRight (false)
, mFast (false), mDragging (false), mMod1 (false)
, mFastFactor (4)
, mDefaultAmbient (0, 0, 0, 0), mHasDefaultAmbient (false)
{
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground);
setFocusPolicy (Qt::StrongFocus);
RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f)
, mRootNode(0)
{
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
osgViewer::CompositeViewer& viewer = CompositeViewer::get();
mSceneMgr->setAmbientLight (Ogre::ColourValue (0,0,0,1));
osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
//ds->setNumMultiSamples(8);
mCamera = mSceneMgr->createCamera("foo");
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->windowName = "";
traits->windowDecoration = true;
traits->x = 0;
traits->y = 0;
traits->width = width();
traits->height = height();
traits->doubleBuffer = true;
traits->alpha = ds->getMinimumNumAlphaBits();
traits->stencil = ds->getMinimumNumStencilBits();
traits->sampleBuffers = ds->getMultiSamples();
traits->samples = ds->getNumMultiSamples();
// Doesn't make much sense as we're running on demand updates, and there seems to be a bug with the refresh rate when running multiple QGLWidgets
traits->vsync = false;
mCamera->setPosition (300, 0, 0);
mCamera->lookAt (0, 0, 0);
mCamera->setNearClipDistance (0.1);
mView = new osgViewer::View;
CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance();
osg::ref_ptr<osgQt::GraphicsWindowQt> window = new osgQt::GraphicsWindowQt(traits.get());
QLayout* layout = new QHBoxLayout(this);
layout->addWidget(window->getGLWidget());
setLayout(layout);
float farClipDist = userSettings.setting("3d-render/far-clip-distance", QString("300000")).toFloat();
mCamera->setFarClipDistance (farClipDist);
mView->getCamera()->setGraphicsContext(window);
mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) );
mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0f, 10000.0f );
mFastFactor = userSettings.setting("scene-input/fast-factor", QString("4")).toInt();
mRootNode = new osg::Group;
mCamera->roll (Ogre::Degree (90));
mView->getCamera()->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
mView->getCamera()->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
setLighting (&mLightingDay);
mView->setSceneData(mRootNode);
mOverlaySystem = OverlaySystem::instance().get();
mSceneMgr->addRenderQueueListener(mOverlaySystem);
QTimer *timer = new QTimer (this);
connect (timer, SIGNAL (timeout()), this, SLOT (update()));
int timerStart = userSettings.setting("scene-input/timer", QString("20")).toInt();
timer->start (timerStart);
/// \todo make shortcut configurable
QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut);
connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest()));
}
CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent)
{
CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode");
/// \todo replace icons
tool->addButton (":scenetoolbar/day", "day",
"Day"
"<ul><li>Cell specific ambient in interiors</li>"
"<li>Low ambient in exteriors</li>"
"<li>Strong directional light source/lir>"
"<li>This mode closely resembles day time in-game</li></ul>");
tool->addButton (":scenetoolbar/night", "night",
"Night"
"<ul><li>Cell specific ambient in interiors</li>"
"<li>Low ambient in exteriors</li>"
"<li>Weak directional light source</li>"
"<li>This mode closely resembles night time in-game</li></ul>");
tool->addButton (":scenetoolbar/bright", "bright",
"Bright"
"<ul><li>Maximum ambient</li>"
"<li>Strong directional light source</li></ul>");
connect (tool, SIGNAL (modeChanged (const std::string&)),
this, SLOT (selectLightingMode (const std::string&)));
return tool;
}
void SceneWidget::setDefaultAmbient (const Ogre::ColourValue& colour)
{
mDefaultAmbient = colour;
mHasDefaultAmbient = true;
if (mLighting)
mLighting->setDefaultAmbient (colour);
}
void SceneWidget::updateOgreWindow()
{
if (mWindow)
{
Ogre::Root::getSingleton().destroyRenderTarget(mWindow);
mWindow = NULL;
}
std::stringstream windowHandle;
#ifdef WIN32
windowHandle << Ogre::StringConverter::toString((uintptr_t)(this->winId()));
#else
windowHandle << this->winId();
#endif
std::stringstream windowTitle;
static int count=0;
windowTitle << ++count;
Ogre::NameValuePairList params;
params.insert(std::make_pair("externalWindowHandle", windowHandle.str()));
params.insert(std::make_pair("title", windowTitle.str()));
std::string antialiasing =
CSMSettings::UserSettings::instance().settingValue("3d-render/antialiasing").toStdString();
if(antialiasing == "MSAA 16") antialiasing = "16";
else if(antialiasing == "MSAA 8") antialiasing = "8";
else if(antialiasing == "MSAA 4") antialiasing = "4";
else if(antialiasing == "MSAA 2") antialiasing = "2";
else antialiasing = "0";
params.insert(std::make_pair("FSAA", antialiasing));
params.insert(std::make_pair("vsync", "false")); // TODO setting
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
params.insert(std::make_pair("macAPI", "cocoa"));
params.insert(std::make_pair("macAPICocoaUseNSView", "true"));
#endif
// Press S to reveal profiling stats
mView->addEventHandler(new osgViewer::StatsHandler);
mView->getCamera()->setCullMask(~(0x1));
viewer.addView(mView);
viewer.setDone(false);
viewer.realize();
}
RenderWidget::~RenderWidget()
{
CompositeViewer::get().removeView(mView);
}
void RenderWidget::flagAsModified()
{
mView->requestRedraw();
}
mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, &params);
mViewport = mWindow->addViewport (mCamera);
mViewport->setBackgroundColour (Ogre::ColourValue (0.3,0.3,0.3,1));
Ogre::Real aspectRatio = Ogre::Real(width()) / Ogre::Real(height());
mCamera->setAspectRatio(aspectRatio);
}
SceneWidget::~SceneWidget()
{
if (mWindow)
Ogre::Root::getSingleton().destroyRenderTarget (mWindow);
if (mSceneMgr)
mSceneMgr->removeRenderQueueListener (mOverlaySystem);
if (mSceneMgr)
Ogre::Root::getSingleton().destroySceneManager (mSceneMgr);
}
void SceneWidget::setVisibilityMask (unsigned int mask)
{
mViewport->setVisibilityMask (mask);
}
void SceneWidget::setNavigation (Navigation *navigation)
{
if ((mNavigation = navigation))
{
mNavigation->setFastModeFactor (mFast ? mFastFactor : 1);
if (mNavigation->activate (mCamera))
mUpdate = true;
}
}
void SceneWidget::addRenderTargetListener(Ogre::RenderTargetListener *listener)
{
mWindow->addListener(listener);
}
void SceneWidget::removeRenderTargetListener(Ogre::RenderTargetListener *listener)
{
mWindow->removeListener(listener);
}
Ogre::Viewport *SceneWidget::getViewport()
{
if (!mWindow)
updateOgreWindow();
return mViewport;
}
Ogre::SceneManager *SceneWidget::getSceneManager()
{
return mSceneMgr;
}
Ogre::Camera *SceneWidget::getCamera()
{
return mCamera;
}
void SceneWidget::flagAsModified()
{
mUpdate = true;
}
void SceneWidget::paintEvent(QPaintEvent* e)
{
if (!mWindow)
updateOgreWindow();
mWindow->update();
e->accept();
}
QPaintEngine* SceneWidget::paintEngine() const
{
// We don't want another paint engine to get in the way.
// So we return nothing.
return NULL;
}
void SceneWidget::resizeEvent(QResizeEvent *e)
{
if (!mWindow)
return;
const QSize &newSize = e->size();
// TODO: Fix Ogre to handle this more consistently (fixed in 1.9)
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
mWindow->resize(newSize.width(), newSize.height());
void RenderWidget::setVisibilityMask(int mask)
{
// 0x1 reserved for separating cull and update visitors
mView->getCamera()->setCullMask(mask<<1);
}
// --------------------------------------------------
CompositeViewer::CompositeViewer()
{
#if QT_VERSION >= 0x050000
// Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4
osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded;
#else
mWindow->windowMovedOrResized();
osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext;
#endif
Ogre::Real aspectRatio = Ogre::Real(newSize.width()) / Ogre::Real(newSize.height());
mCamera->setAspectRatio(aspectRatio);
}
bool SceneWidget::event(QEvent *e)
{
if (e->type() == QEvent::WinIdChange)
{
// I haven't actually seen this happen yet.
if (mWindow)
updateOgreWindow();
}
return QWidget::event(e);
}
void SceneWidget::keyPressEvent (QKeyEvent *event)
{
switch (event->key())
{
case Qt::Key_W: mKeyForward = true; break;
case Qt::Key_S: mKeyBackward = true; break;
case Qt::Key_A: mKeyLeft = true; break;
case Qt::Key_D: mKeyRight = true; break;
case Qt::Key_Q: mKeyRollLeft = true; break;
case Qt::Key_E: mKeyRollRight = true; break;
case Qt::Key_Control: mMod1 = true; break;
case Qt::Key_Shift:
mFast = true;
if (mNavigation)
mNavigation->setFastModeFactor (mFastFactor);
break;
default: QWidget::keyPressEvent (event);
}
}
void SceneWidget::keyReleaseEvent (QKeyEvent *event)
{
switch (event->key())
{
case Qt::Key_W: mKeyForward = false; break;
case Qt::Key_S: mKeyBackward = false; break;
case Qt::Key_A: mKeyLeft = false; break;
case Qt::Key_D: mKeyRight = false; break;
case Qt::Key_Q: mKeyRollLeft = false; break;
case Qt::Key_E: mKeyRollRight = false; break;
case Qt::Key_Control: mMod1 = false; break;
case Qt::Key_Shift:
mFast = false;
if (mNavigation)
mNavigation->setFastModeFactor (1);
break;
default: QWidget::keyReleaseEvent (event);
}
}
void SceneWidget::wheelEvent (QWheelEvent *event)
{
if (mNavigation)
if (event->delta())
if (mNavigation->wheelMoved (event->delta()))
mUpdate = true;
}
void SceneWidget::leaveEvent (QEvent *event)
{
mDragging = false;
}
void SceneWidget::mouseMoveEvent (QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
{
if (mDragging)
{
QPoint diff = mOldPos-event->pos();
mOldPos = event->pos();
if (mNavigation)
if (mNavigation->mouseMoved (diff, mMod1 ? 1 : 0))
mUpdate = true;
}
else
{
mDragging = true;
mOldPos = event->pos();
}
}
}
void SceneWidget::mouseReleaseEvent (QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
mDragging = false;
}
void SceneWidget::focusOutEvent (QFocusEvent *event)
{
mKeyForward = false;
mKeyBackward = false;
mKeyLeft = false;
mKeyRight = false;
mFast = false;
mMod1 = false;
QWidget::focusOutEvent (event);
}
void SceneWidget::update()
{
if (mNavigation)
{
int horizontal = 0;
int vertical = 0;
if (mKeyForward && !mKeyBackward)
vertical = 1;
else if (!mKeyForward && mKeyBackward)
vertical = -1;
if (mKeyLeft && !mKeyRight)
horizontal = -1;
else if (!mKeyLeft && mKeyRight)
horizontal = 1;
if (horizontal || vertical)
if (mNavigation->handleMovementKeys (vertical, horizontal))
mUpdate = true;
int roll = 0;
if (mKeyRollLeft && !mKeyRollRight)
roll = 1;
else if (!mKeyRollLeft && mKeyRollRight)
roll = -1;
if (roll)
if (mNavigation->handleRollKeys (roll))
mUpdate = true;
}
if (mUpdate && mWindow)
{
mUpdate = false;
mWindow->update();
updateOverlay();
}
}
void SceneWidget::updateScene()
{
flagAsModified();
}
void SceneWidget::updateOverlay()
{ }
void SceneWidget::setLighting (Lighting *lighting)
{
if (mLighting)
mLighting->deactivate();
mLighting = lighting;
mLighting->activate (mSceneMgr, mHasDefaultAmbient ? &mDefaultAmbient : 0);
if (mWindow)
mWindow->update();
}
void SceneWidget::selectLightingMode (const std::string& mode)
{
if (mode=="day")
setLighting (&mLightingDay);
else if (mode=="night")
setLighting (&mLightingNight);
else if (mode=="bright")
setLighting (&mLightingBright);
}
void SceneWidget::updateUserSetting (const QString &key, const QStringList &list)
{
if(key.contains(QRegExp("^\\b(Objects|Shader|Scene)", Qt::CaseInsensitive)))
flagAsModified();
if(key == "3d-render/far-clip-distance" && !list.empty())
{
if(mCamera->getFarClipDistance() != list.at(0).toFloat())
mCamera->setFarClipDistance(list.at(0).toFloat());
}
// minimise unnecessary ogre window creation by updating only when there is a change
if(key == "3d-render/antialiasing")
{
unsigned int aa = mWindow->getFSAA();
unsigned int antialiasing = 0;
if(!list.empty())
{
if(list.at(0) == "MSAA 16") antialiasing = 16;
else if(list.at(0) == "MSAA 8") antialiasing = 8;
else if(list.at(0) == "MSAA 4") antialiasing = 4;
else if(list.at(0) == "MSAA 2") antialiasing = 2;
}
if(aa != antialiasing)
updateOgreWindow();
}
}
setThreadingModel(threadingModel);
// disable the default setting of viewer.done() by pressing Escape.
setKeyEventSetsDone(0);
// Only render when the camera position changed, or content flagged dirty
//setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND);
setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS);
connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) );
mTimer.start( 10 );
}
CompositeViewer &CompositeViewer::get()
{
static CompositeViewer sThis;
return sThis;
}
void CompositeViewer::update()
{
frame();
}
// ---------------------------------------------------
SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, Qt::WindowFlags f)
: RenderWidget(parent, f)
, mSceneManager(sceneManager)
, mLighting(NULL)
, mHasDefaultAmbient(false)
{
// we handle lighting manually
mView->setLightingMode(osgViewer::View::NO_LIGHT);
setLighting(&mLightingDay);
}
SceneWidget::~SceneWidget()
{
// Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects
mSceneManager->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
}
void SceneWidget::setLighting(Lighting *lighting)
{
if (mLighting)
mLighting->deactivate();
mLighting = lighting;
mLighting->activate (mRootNode);
osg::Vec4f ambient = mLighting->getAmbientColour(mHasDefaultAmbient ? &mDefaultAmbient : 0);
setAmbient(ambient);
flagAsModified();
}
void SceneWidget::setAmbient(const osg::Vec4f& ambient)
{
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
osg::ref_ptr<osg::LightModel> lightmodel = new osg::LightModel;
lightmodel->setAmbientIntensity(ambient);
stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
stateset->setMode(GL_LIGHT0, osg::StateAttribute::ON);
stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON);
mRootNode->setStateSet(stateset);
}
void SceneWidget::selectLightingMode (const std::string& mode)
{
if (mode=="day")
setLighting (&mLightingDay);
else if (mode=="night")
setLighting (&mLightingNight);
else if (mode=="bright")
setLighting (&mLightingBright);
}
CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent)
{
CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode");
/// \todo replace icons
tool->addButton (":scenetoolbar/day", "day",
"Day"
"<ul><li>Cell specific ambient in interiors</li>"
"<li>Low ambient in exteriors</li>"
"<li>Strong directional light source</li>"
"<li>This mode closely resembles day time in-game</li></ul>");
tool->addButton (":scenetoolbar/night", "night",
"Night"
"<ul><li>Cell specific ambient in interiors</li>"
"<li>Low ambient in exteriors</li>"
"<li>Weak directional light source</li>"
"<li>This mode closely resembles night time in-game</li></ul>");
tool->addButton (":scenetoolbar/bright", "bright",
"Bright"
"<ul><li>Maximum ambient</li>"
"<li>Strong directional light source</li></ul>");
connect (tool, SIGNAL (modeChanged (const std::string&)),
this, SLOT (selectLightingMode (const std::string&)));
return tool;
}
void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour)
{
mDefaultAmbient = colour;
mHasDefaultAmbient = true;
setAmbient(mLighting->getAmbientColour(&mDefaultAmbient));
}
}

@ -2,21 +2,23 @@
#define OPENCS_VIEW_SCENEWIDGET_H
#include <QWidget>
#include <OgreColourValue.h>
#include <QTimer>
#include "lightingday.hpp"
#include "lightingnight.hpp"
#include "lightingbright.hpp"
namespace Ogre
#include <osgViewer/View>
#include <osgViewer/CompositeViewer>
namespace Resource
{
class Camera;
class SceneManager;
class RenderWindow;
class Viewport;
class OverlaySystem;
class RenderTargetListener;
}
namespace osg
{
class Group;
}
namespace CSVWidget
@ -27,114 +29,81 @@ namespace CSVWidget
namespace CSVRender
{
class Navigation;
class Lighting;
class SceneWidget : public QWidget
class RenderWidget : public QWidget
{
Q_OBJECT
public:
SceneWidget(QWidget *parent);
virtual ~SceneWidget();
QPaintEngine* paintEngine() const;
CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent);
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
/// is the responsibility of the calling function.
virtual void setVisibilityMask (unsigned int mask);
virtual void updateScene();
protected:
void setNavigation (Navigation *navigation);
///< \attention The ownership of \a navigation is not transferred to *this.
void addRenderTargetListener(Ogre::RenderTargetListener *listener);
public:
RenderWidget(QWidget* parent = 0, Qt::WindowFlags f = 0);
virtual ~RenderWidget();
void removeRenderTargetListener(Ogre::RenderTargetListener *listener);
void flagAsModified();
Ogre::Viewport *getViewport();
void setVisibilityMask(int mask);
Ogre::SceneManager *getSceneManager();
protected:
Ogre::Camera *getCamera();
osg::ref_ptr<osgViewer::View> mView;
void flagAsModified();
osg::Group* mRootNode;
void setDefaultAmbient (const Ogre::ColourValue& colour);
///< \note The actual ambient colour may differ based on lighting settings.
virtual void updateOverlay();
virtual void mouseReleaseEvent (QMouseEvent *event);
virtual void mouseMoveEvent (QMouseEvent *event);
void wheelEvent (QWheelEvent *event);
void keyPressEvent (QKeyEvent *event);
QTimer mTimer;
};
private:
void paintEvent(QPaintEvent* e);
void resizeEvent(QResizeEvent* e);
bool event(QEvent* e);
// Extension of RenderWidget to support lighting mode selection & toolbar
class SceneWidget : public RenderWidget
{
Q_OBJECT
public:
SceneWidget(Resource::SceneManager* sceneManager, QWidget* parent = 0, Qt::WindowFlags f = 0);
virtual ~SceneWidget();
void keyReleaseEvent (QKeyEvent *event);
CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent);
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
/// is the responsibility of the calling function.
void focusOutEvent (QFocusEvent *event);
void setDefaultAmbient (const osg::Vec4f& colour);
///< \note The actual ambient colour may differ based on lighting settings.
void leaveEvent (QEvent *event);
protected:
void setLighting (Lighting *lighting);
///< \attention The ownership of \a lighting is not transferred to *this.
void updateOgreWindow();
void setAmbient(const osg::Vec4f& ambient);
void setLighting (Lighting *lighting);
///< \attention The ownership of \a lighting is not transferred to *this.
Resource::SceneManager* mSceneManager;
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
Ogre::RenderWindow* mWindow;
Ogre::Viewport *mViewport;
Ogre::OverlaySystem *mOverlaySystem;
Lighting* mLighting;
Navigation *mNavigation;
Lighting *mLighting;
bool mUpdate;
bool mKeyForward;
bool mKeyBackward;
bool mKeyLeft;
bool mKeyRight;
bool mKeyRollLeft;
bool mKeyRollRight;
bool mFast;
bool mDragging;
bool mMod1;
QPoint mOldPos;
int mFastFactor;
Ogre::ColourValue mDefaultAmbient;
bool mHasDefaultAmbient;
LightingDay mLightingDay;
LightingNight mLightingNight;
LightingBright mLightingBright;
osg::Vec4f mDefaultAmbient;
bool mHasDefaultAmbient;
LightingDay mLightingDay;
LightingNight mLightingNight;
LightingBright mLightingBright;
public slots:
private slots:
void updateUserSetting (const QString &key, const QStringList &list);
void selectLightingMode (const std::string& mode);
};
private slots:
void update();
// There are rendering glitches when using multiple Viewer instances, work around using CompositeViewer with multiple views
class CompositeViewer : public QObject, public osgViewer::CompositeViewer
{
Q_OBJECT
public:
CompositeViewer();
void selectLightingMode (const std::string& mode);
static CompositeViewer& get();
signals:
QTimer mTimer;
void focusToolbarRequest();
public slots:
void update();
};
}
#endif

@ -4,7 +4,8 @@ namespace CSVRender
{
TerrainStorage::TerrainStorage(const CSMWorld::Data &data)
: mData(data)
: ESMTerrain::Storage(data.getResourceSystem()->getVFS())
, mData(data)
{
}

@ -1,359 +0,0 @@
#include "textoverlay.hpp"
#include <OgreCamera.h>
#include <OgreMaterialManager.h>
#include <OgreTechnique.h>
#include <OgreOverlayManager.h>
#include <OgreOverlayContainer.h>
#include <OgreFontManager.h>
#include <OgreTextAreaOverlayElement.h>
#include <OgreEntity.h>
#include <OgreViewport.h>
#include <OgreRoot.h>
#include <OgreHardwarePixelBuffer.h>
namespace CSVRender
{
// Things to do:
// - configurable font size in pixels (automatically calulate everything else from it)
// - configurable texture to use
// - try material script
// - decide whether to use QPaint (http://www.ogre3d.org/tikiwiki/Ogre+overlays+using+Qt)
// http://www.ogre3d.org/tikiwiki/ObjectTextDisplay
// http://www.ogre3d.org/tikiwiki/MovableTextOverlay
// http://www.ogre3d.org/tikiwiki/Creating+dynamic+textures
// http://www.ogre3d.org/tikiwiki/ManualObject
TextOverlay::TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String& id)
: mOverlay(0), mCaption(""), mDesc(""), mObj(obj), mCamera(camera), mFontHeight(16), mId(id)
, mEnabled(true), mOnScreen(false), mInstance(0) // FIXME: make font height configurable
{
if(id == "" || !camera || !obj)
throw std::runtime_error("TextOverlay could not be created.");
// setup font
Ogre::FontManager &fontMgr = Ogre::FontManager::getSingleton();
if (fontMgr.resourceExists("DejaVuLGC"))
mFont = fontMgr.getByName("DejaVuLGC","General");
else
{
mFont = fontMgr.create("DejaVuLGC","General");
mFont->setType(Ogre::FT_TRUETYPE);
mFont->setSource("DejaVuLGCSansMono.ttf");
mFont->setTrueTypeSize(mFontHeight);
mFont->setTrueTypeResolution(96);
}
if(!mFont.isNull())
mFont->load();
else
throw std::runtime_error("TextOverlay font not loaded.");
// setup overlay
Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton();
mOverlay = overlayMgr.getByName("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance));
// FIXME: this logic is badly broken as it is possible to delete an earlier instance
while(mOverlay != NULL)
{
mInstance++;
mOverlay = overlayMgr.getByName("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance));
}
mOverlay = overlayMgr.create("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance));
// create texture
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTransBlue");
if(texture.isNull())
{
texture = Ogre::TextureManager::getSingleton().createManual(
"DynamicTransBlue", // name
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D, // type
8, 8, // width & height
0, // number of mipmaps
Ogre::PF_BYTE_BGRA, // pixel format
Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for
// textures updated very often (e.g. each frame)
Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer();
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);
// Fill in some pixel data. This will give a semi-transparent blue,
// but this is of course dependent on the chosen pixel format.
for (size_t j = 0; j < 8; j++)
{
for(size_t i = 0; i < 8; i++)
{
*pDest++ = 255; // B
*pDest++ = 0; // G
*pDest++ = 0; // R
*pDest++ = 63; // A
}
pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format);
}
pixelBuffer->unlock();
}
// setup material for containers
Ogre::MaterialPtr mQuadMaterial = Ogre::MaterialManager::getSingleton().getByName(
"TransOverlayMaterial");
if(mQuadMaterial.isNull())
{
Ogre::MaterialPtr mQuadMaterial = Ogre::MaterialManager::getSingleton().create(
"TransOverlayMaterial",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true );
Ogre::Pass *pass = mQuadMaterial->getTechnique( 0 )->getPass( 0 );
pass->setLightingEnabled( false );
pass->setDepthWriteEnabled( false );
pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA );
Ogre::TextureUnitState *tex = pass->createTextureUnitState("MyCustomState", 0);
tex->setTextureName("DynamicTransBlue");
tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC );
mQuadMaterial->load();
}
mContainer = static_cast<Ogre::OverlayContainer*>(overlayMgr.createOverlayElement(
"Panel", "container"+mId +"#"+Ogre::StringConverter::toString(mInstance)));
mContainer->setMaterialName("TransOverlayMaterial");
mOverlay->add2D(mContainer);
// setup text area overlay element
mElement = static_cast<Ogre::TextAreaOverlayElement*>(overlayMgr.createOverlayElement(
"TextArea", "text"+mId +"#"+Ogre::StringConverter::toString(mInstance)));
mElement->setMetricsMode(Ogre::GMM_RELATIVE);
mElement->setDimensions(1.0, 1.0);
mElement->setMetricsMode(Ogre::GMM_PIXELS);
mElement->setPosition(2*fontHeight()/3, 1.3*fontHeight()/3); // 1.3 & 2 = fudge factor
mElement->setFontName("DejaVuLGC");
mElement->setCharHeight(fontHeight()); // NOTE: seems that this is required as well as font->setTrueTypeSize()
mElement->setHorizontalAlignment(Ogre::GHA_LEFT);
//mElement->setColour(Ogre::ColourValue(1.0, 1.0, 1.0)); // R, G, B
mElement->setColour(Ogre::ColourValue(1.0, 1.0, 0)); // yellow
mContainer->addChild(mElement);
mOverlay->show();
}
void TextOverlay::getScreenCoordinates(const Ogre::Vector3& position, Ogre::Real& x, Ogre::Real& y)
{
Ogre::Vector3 hcsPosition = mCamera->getProjectionMatrix() * (mCamera->getViewMatrix() * position);
x = 1.0f - ((hcsPosition.x * 0.5f) + 0.5f); // 0 <= x <= 1 // left := 0,right := 1
y = ((hcsPosition.y * 0.5f) + 0.5f); // 0 <= y <= 1 // bottom := 0,top := 1
}
void TextOverlay::getMinMaxEdgesOfAABBIn2D(float& MinX, float& MinY, float& MaxX, float& MaxY,
bool top)
{
MinX = 0, MinY = 0, MaxX = 0, MaxY = 0;
float X[4]; // the 2D dots of the AABB in screencoordinates
float Y[4];
if(!mObj->isInScene())
return;
const Ogre::AxisAlignedBox &AABB = mObj->getWorldBoundingBox(true); // the AABB of the target
Ogre::Vector3 cornersOfAABB[4];
if(top)
{
cornersOfAABB[0] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_LEFT_TOP);
cornersOfAABB[1] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_RIGHT_TOP);
cornersOfAABB[2] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_LEFT_TOP);
cornersOfAABB[3] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_RIGHT_TOP);
}
else
{
cornersOfAABB[0] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_LEFT_BOTTOM);
cornersOfAABB[1] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_RIGHT_BOTTOM);
cornersOfAABB[2] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_LEFT_BOTTOM);
cornersOfAABB[3] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_RIGHT_BOTTOM);
}
//The normal vector of the plane. This points directly infront of the camera.
Ogre::Vector3 cameraPlainNormal = mCamera->getDerivedOrientation().zAxis();
//the plane that devides the space before and behind the camera.
Ogre::Plane CameraPlane = Ogre::Plane(cameraPlainNormal, mCamera->getDerivedPosition());
for (int i = 0; i < 4; i++)
{
X[i] = 0;
Y[i] = 0;
getScreenCoordinates(cornersOfAABB[i],X[i],Y[i]); // transfor into 2d dots
if (CameraPlane.getSide(cornersOfAABB[i]) == Ogre::Plane::NEGATIVE_SIDE)
{
if (i == 0) // accept the first set of values, no matter how bad it might be.
{
MinX = X[i];
MinY = Y[i];
MaxX = X[i];
MaxY = Y[i];
}
else // now compare if you get "better" values
{
if (MinX > X[i]) MinX = X[i];
if (MinY > Y[i]) MinY = Y[i];
if (MaxX < X[i]) MaxX = X[i];
if (MaxY < Y[i]) MaxY = Y[i];
}
}
else
{
MinX = 0;
MinY = 0;
MaxX = 0;
MaxY = 0;
break;
}
}
}
TextOverlay::~TextOverlay()
{
Ogre::OverlayManager::OverlayMapIterator iter = Ogre::OverlayManager::getSingleton().getOverlayIterator();
if(!iter.hasMoreElements())
mOverlay->hide();
Ogre::OverlayManager *overlayMgr = Ogre::OverlayManager::getSingletonPtr();
mContainer->removeChild("text"+mId+"#"+Ogre::StringConverter::toString(mInstance));
mOverlay->remove2D(mContainer);
if(!iter.hasMoreElements())
overlayMgr->destroy(mOverlay);
}
void TextOverlay::show(bool show)
{
if(show && mOnScreen)
mContainer->show();
else
mContainer->hide();
}
void TextOverlay::enable(bool enable)
{
if(enable == mOverlay->isVisible())
return;
mEnabled = enable;
if(enable)
mOverlay->show();
else
mOverlay->hide();
}
bool TextOverlay::isEnabled()
{
return mEnabled;
}
void TextOverlay::setCaption(const Ogre::String& text)
{
if(mCaption == text)
return;
mCaption = text;
mElement->setCaption(text);
}
void TextOverlay::setDesc(const Ogre::String& text)
{
if(mDesc == text)
return;
mDesc = text;
mElement->setCaption(mCaption + ((text == "") ? "" : ("\n" + text)));
}
Ogre::FontPtr TextOverlay::getFont()
{
return mFont;
}
int TextOverlay::textWidth()
{
float captionWidth = 0;
float descWidth = 0;
for(Ogre::String::const_iterator i = mCaption.begin(); i < mCaption.end(); ++i)
{
if(*i == 0x0020)
captionWidth += getFont()->getGlyphAspectRatio(0x0030);
else
captionWidth += getFont()->getGlyphAspectRatio(*i);
}
for(Ogre::String::const_iterator i = mDesc.begin(); i < mDesc.end(); ++i)
{
if(*i == 0x0020)
descWidth += getFont()->getGlyphAspectRatio(0x0030);
else
descWidth += getFont()->getGlyphAspectRatio(*i);
}
captionWidth *= fontHeight();
descWidth *= fontHeight();
return (int) std::max(captionWidth, descWidth);
}
int TextOverlay::fontHeight()
{
return mFontHeight;
}
void TextOverlay::update()
{
float min_x, max_x, min_y, max_y;
getMinMaxEdgesOfAABBIn2D(min_x, min_y, max_x, max_y, false);
if ((min_x>0.0) && (max_x<1.0) && (min_y>0.0) && (max_y<1.0))
{
mOnScreen = true;
mContainer->show();
}
else
{
mOnScreen = false;
mContainer->hide();
return;
}
getMinMaxEdgesOfAABBIn2D(min_x, min_y, max_x, max_y);
Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton();
float viewportWidth = std::max(overlayMgr.getViewportWidth(), 1); // zero at the start
float viewportHeight = std::max(overlayMgr.getViewportHeight(), 1); // zero at the start
int width = fontHeight()*2/3 + textWidth() + fontHeight()*2/3; // add margins
int height = fontHeight()/3 + fontHeight() + fontHeight()/3;
if(mDesc != "")
height = fontHeight()/3 + 2*fontHeight() + fontHeight()/3;
float relTextWidth = width / viewportWidth;
float relTextHeight = height / viewportHeight;
float posX = 1 - (min_x + max_x + relTextWidth)/2;
float posY = 1 - max_y - (relTextHeight-fontHeight()/3/viewportHeight);
mContainer->setMetricsMode(Ogre::GMM_RELATIVE);
mContainer->setPosition(posX, posY);
mContainer->setDimensions(relTextWidth, relTextHeight);
mPos = QRect(posX*viewportWidth, posY*viewportHeight, width, height);
}
QRect TextOverlay::container()
{
return mPos;
}
}

@ -1,66 +0,0 @@
#ifndef OPENCS_VIEW_TEXTOVERLAY_H
#define OPENCS_VIEW_TEXTOVERLAY_H
#include <QRect>
#include <OgreString.h>
#include <OgreFont.h>
namespace Ogre
{
class MovableObject;
class Camera;
class Font;
class Overlay;
class OverlayContainer;
class TextAreaOverlayElement;
}
namespace CSVRender
{
class TextOverlay
{
Ogre::Overlay* mOverlay;
Ogre::OverlayContainer* mContainer;
Ogre::TextAreaOverlayElement* mElement;
Ogre::String mCaption;
Ogre::String mDesc;
const Ogre::MovableObject* mObj;
const Ogre::Camera* mCamera;
Ogre::FontPtr mFont;
int mFontHeight; // in pixels
Ogre::String mId;
QRect mPos;
bool mEnabled;
bool mOnScreen;
int mInstance;
Ogre::FontPtr getFont();
int textWidth();
int fontHeight();
void getScreenCoordinates(const Ogre::Vector3& position, Ogre::Real& x, Ogre::Real& y);
void getMinMaxEdgesOfAABBIn2D(float& MinX, float& MinY, float& MaxX, float& MaxY,
bool top = true);
public:
TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String &id);
virtual ~TextOverlay();
void enable(bool enable); // controlled from scene widget toolbar visibility mask
void show(bool show); // for updating from render target listener
bool isEnabled();
void setCaption(const Ogre::String& text);
void setDesc(const Ogre::String& text);
void update();
QRect container(); // for detection of mouse click on the overlay
Ogre::String getCaption() { return mCaption; } // FIXME: debug
Ogre::String getDesc() { return mDesc; }
};
}
#endif // OPENCS_VIEW_TEXTOVERLAY_H

@ -3,11 +3,12 @@
#include <sstream>
#include <OgreColourValue.h>
#include <OgreCamera.h>
#include <osgGA/TrackballManipulator>
#include <QtGui/qevent.h>
#include <components/sceneutil/util.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
@ -24,8 +25,8 @@ void CSVRender::UnpagedWorldspaceWidget::update()
const CSMWorld::Record<CSMWorld::Cell>& record =
dynamic_cast<const CSMWorld::Record<CSMWorld::Cell>&> (mCellsModel->getRecord (mCellId));
Ogre::ColourValue colour;
colour.setAsABGR (record.get().mAmbi.mAmbient);
osg::Vec4f colour = SceneUtil::colourFromRGB(record.get().mAmbi.mAmbient);
setDefaultAmbient (colour);
/// \todo deal with mSunlight and mFog/mForDensity
@ -49,7 +50,9 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string&
update();
mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics()));
mCell.reset (new Cell (document.getData(), mRootNode, mCellId));
mView->setCameraManipulator(new osgGA::TrackballManipulator);
}
void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft,
@ -91,7 +94,8 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld:
return false;
mCellId = data.begin()->getId();
mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics()));
mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId));
update();
emit cellChanged(*data.begin());
@ -163,13 +167,13 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons (
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
{
Ogre::Vector3 position = getCamera()->getPosition();
osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans();
std::ostringstream stream;
stream
<< "player->positionCell "
<< position.x << ", " << position.y << ", " << position.z
<< position.x() << ", " << position.y() << ", " << position.z()
<< ", 0, \"" << mCellId << "\"";
return stream.str();

@ -3,12 +3,11 @@
#include <algorithm>
#include <OgreSceneNode.h>
#include <OgreSceneManager.h>
#include <OgreEntity.h>
#include <QtGui/qevent.h>
#include <osgGA/TrackballManipulator>
#include <osgGA/FirstPersonManipulator>
#include "../../model/world/universalid.hpp"
#include "../../model/world/idtable.hpp"
@ -16,13 +15,11 @@
#include "../widget/scenetooltoggle2.hpp"
#include "../widget/scenetoolrun.hpp"
#include "../world/physicssystem.hpp"
#include "elements.hpp"
#include "editmode.hpp"
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
: SceneWidget (parent), mSceneElements(0), mRun(0), mDocument(document), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>()), mMouse(0),
: SceneWidget (document.getData().getResourceSystem()->getSceneManager(), parent), mSceneElements(0), mRun(0), mDocument(document),
mInteractionMask (0)
{
setAcceptDrops(true);
@ -54,33 +51,27 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&)));
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
mPhysics = document.getPhysics(); // create physics if one doesn't exist
mPhysics->addSceneManager(getSceneManager(), this);
mMouse = new MouseState(this);
}
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
{
delete mMouse;
mPhysics->removeSceneManager(getSceneManager());
}
void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
{
if (mode=="1st")
setNavigation (&m1st);
mView->setCameraManipulator(new osgGA::FirstPersonManipulator);
else if (mode=="free")
setNavigation (&mFree);
mView->setCameraManipulator(new osgGA::FirstPersonManipulator);
else if (mode=="orbit")
setNavigation (&mOrbit);
mView->setCameraManipulator(new osgGA::OrbitManipulator);
}
void CSVRender::WorldspaceWidget::useViewHint (const std::string& hint) {}
void CSVRender::WorldspaceWidget::selectDefaultNavigationMode()
{
setNavigation (&m1st);
mView->setCameraManipulator(new osgGA::FirstPersonManipulator);
}
CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
@ -368,16 +359,16 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
{
if(event->buttons() & Qt::RightButton)
{
mMouse->mouseMoveEvent(event);
//mMouse->mouseMoveEvent(event);
}
SceneWidget::mouseMoveEvent(event);
RenderWidget::mouseMoveEvent(event);
}
void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event)
{
if(event->buttons() & Qt::RightButton)
{
mMouse->mousePressEvent(event);
//mMouse->mousePressEvent(event);
}
//SceneWidget::mousePressEvent(event);
}
@ -386,37 +377,39 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event)
{
if(event->button() == Qt::RightButton)
{
/*
if(!getViewport())
{
SceneWidget::mouseReleaseEvent(event);
return;
}
mMouse->mouseReleaseEvent(event);
*/
//mMouse->mouseReleaseEvent(event);
}
SceneWidget::mouseReleaseEvent(event);
RenderWidget::mouseReleaseEvent(event);
}
void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event)
{
if(event->button() == Qt::RightButton)
{
mMouse->mouseDoubleClickEvent(event);
//mMouse->mouseDoubleClickEvent(event);
}
//SceneWidget::mouseDoubleClickEvent(event);
}
void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event)
{
if(!mMouse->wheelEvent(event))
SceneWidget::wheelEvent(event);
//if(!mMouse->wheelEvent(event))
RenderWidget::wheelEvent(event);
}
void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event)
{
if(event->key() == Qt::Key_Escape)
{
mMouse->cancelDrag();
//mMouse->cancelDrag();
}
else
SceneWidget::keyPressEvent(event);
RenderWidget::keyPressEvent(event);
}

@ -4,11 +4,7 @@
#include <boost/shared_ptr.hpp>
#include "scenewidget.hpp"
#include "mousestate.hpp"
#include "navigation1st.hpp"
#include "navigationfree.hpp"
#include "navigationorbit.hpp"
#include <apps/opencs/model/doc/document.hpp>
#include <apps/opencs/model/world/tablemimedata.hpp>
@ -25,25 +21,15 @@ namespace CSVWidget
class SceneToolRun;
}
namespace CSVWorld
{
class PhysicsSystem;
}
namespace CSVRender
{
class WorldspaceWidget : public SceneWidget
{
Q_OBJECT
CSVRender::Navigation1st m1st;
CSVRender::NavigationFree mFree;
CSVRender::NavigationOrbit mOrbit;
CSVWidget::SceneToolToggle2 *mSceneElements;
CSVWidget::SceneToolRun *mRun;
CSMDoc::Document& mDocument;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
MouseState *mMouse;
unsigned int mInteractionMask;
public:

@ -0,0 +1,28 @@
#include "completerpopup.hpp"
CSVWidget::CompleterPopup::CompleterPopup(QWidget *parent)
: QListView(parent)
{
setEditTriggers(QAbstractItemView::NoEditTriggers);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::SingleSelection);
}
int CSVWidget::CompleterPopup::sizeHintForRow(int row) const
{
if (model() == NULL)
{
return -1;
}
if (row < 0 || row >= model()->rowCount())
{
return -1;
}
ensurePolished();
QModelIndex index = model()->index(row, modelColumn());
QStyleOptionViewItem option = viewOptions();
QAbstractItemDelegate *delegate = itemDelegate(index);
return delegate->sizeHint(option, index).height();
}

@ -0,0 +1,17 @@
#ifndef CSV_WIDGET_COMPLETERPOPUP_HPP
#define CSV_WIDGET_COMPLETERPOPUP_HPP
#include <QListView>
namespace CSVWidget
{
class CompleterPopup : public QListView
{
public:
CompleterPopup(QWidget *parent = 0);
virtual int sizeHintForRow(int row) const;
};
}
#endif

@ -0,0 +1,39 @@
#include "idcompletiondelegate.hpp"
#include "../../model/world/idcompletionmanager.hpp"
CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent)
: CommandDelegate(dispatcher, document, parent)
{}
QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
return createEditor(parent, option, index, getDisplayTypeFromIndex(index));
}
QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index,
CSMWorld::ColumnBase::Display display) const
{
if (!index.data(Qt::EditRole).isValid() && !index.data(Qt::DisplayRole).isValid())
{
return NULL;
}
CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager();
DropLineEdit *editor = new DropLineEdit(parent);
editor->setCompleter(completionManager.getCompleter(display).get());
return editor;
}
CSVWorld::CommandDelegate *CSVWorld::IdCompletionDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent) const
{
return new IdCompletionDelegate(dispatcher, document, parent);
}

@ -0,0 +1,36 @@
#ifndef CSV_WORLD_IDCOMPLETIONDELEGATE_HPP
#define CSV_WORLD_IDCOMPLETIONDELEGATE_HPP
#include "util.hpp"
namespace CSVWorld
{
/// \brief Enables the Id completion for a column
class IdCompletionDelegate : public CommandDelegate
{
public:
IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent);
virtual QWidget *createEditor (QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
virtual QWidget *createEditor (QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index,
CSMWorld::ColumnBase::Display display) const;
};
class IdCompletionDelegateFactory : public CommandDelegateFactory
{
public:
virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
};
}
#endif

@ -1,324 +0,0 @@
#include "physicssystem.hpp"
#include <iostream>
#include <OgreRay.h>
#include <OgreCamera.h>
#include <OgreSceneManager.h>
#include <openengine/bullet/physic.hpp>
#include <components/nifbullet/bulletnifloader.hpp>
#include "../../model/settings/usersettings.hpp"
#include "../render/elements.hpp"
namespace CSVWorld
{
PhysicsSystem::PhysicsSystem()
{
// Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true);
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
}
PhysicsSystem::~PhysicsSystem()
{
delete mEngine;
}
// looks up the scene manager based on the scene node name (inefficient)
// NOTE: referenceId is assumed to be unique per document
// NOTE: searching is done here rather than after rayTest, hence slower to load but
// faster to find (guessing, not verified w/ perf test)
void PhysicsSystem::addObject(const std::string &mesh,
const std::string &sceneNodeName, const std::string &referenceId, float scale,
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable)
{
Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName);
if(sceneManager)
{
// update maps (NOTE: sometimes replaced)
mSceneNodeToRefId[sceneNodeName] = referenceId;
mSceneNodeToMesh[sceneNodeName] = mesh;
mRefIdToSceneNode[referenceId][sceneManager] = sceneNodeName;
}
else
{
std::cerr << "Attempt to add an object without a corresponding SceneManager: "
+ referenceId + " : " + sceneNodeName << std::endl;
return;
}
// update physics, only one physics model per referenceId
if(mEngine->getRigidBody(referenceId, true) == NULL)
{
mEngine->createAndAdjustRigidBody(mesh,
referenceId, scale, position, rotation,
0, // scaledBoxTranslation
0, // boxRotation
true, // raycasting
placeable);
}
}
// normal delete (e.g closing a scene subview or ~Object())
// the scene node is destroyed so the mappings should be removed
//
// TODO: should think about using some kind of reference counting within RigidBody
void PhysicsSystem::removeObject(const std::string &sceneNodeName)
{
std::string referenceId = mSceneNodeToRefId[sceneNodeName];
if(referenceId != "")
{
mSceneNodeToRefId.erase(sceneNodeName);
mSceneNodeToMesh.erase(sceneNodeName);
// find which SceneManager has this object
Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName);
if(!sceneManager)
{
std::cerr << "Attempt to remove an object without a corresponding SceneManager: "
+ sceneNodeName << std::endl;
return;
}
// illustration: erase the object "K" from the object map
//
// RidigBody SubView Ogre
// --------------- -------------- -------------
// ReferenceId "A" (SceneManager X SceneNode "J")
// (SceneManager Y SceneNode "K") <--- erase
// (SceneManager Z SceneNode "L")
//
// ReferenceId "B" (SceneManager X SceneNode "M")
// (SceneManager Y SceneNode "N") <--- notice not deleted
// (SceneManager Z SceneNode "O")
std::map<std::string, std::map<Ogre::SceneManager *, std::string> >::iterator itRef =
mRefIdToSceneNode.begin();
for(; itRef != mRefIdToSceneNode.end(); ++itRef)
{
if((*itRef).second.find(sceneManager) != (*itRef).second.end())
{
(*itRef).second.erase(sceneManager);
break;
}
}
// check whether the physics model should be deleted
if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end())
{
mEngine->removeRigidBody(referenceId);
mEngine->deleteRigidBody(referenceId);
}
}
}
// Object::clear() is called when reference data is changed. It clears all
// contents of the SceneNode and removes the physics object
//
// A new physics object will be created and assigned to this sceneNodeName by
// Object::update()
void PhysicsSystem::removePhysicsObject(const std::string &sceneNodeName)
{
std::string referenceId = mSceneNodeToRefId[sceneNodeName];
if(referenceId != "")
{
mEngine->removeRigidBody(referenceId);
mEngine->deleteRigidBody(referenceId);
}
}
void PhysicsSystem::replaceObject(const std::string &sceneNodeName, float scale,
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable)
{
std::string referenceId = mSceneNodeToRefId[sceneNodeName];
std::string mesh = mSceneNodeToMesh[sceneNodeName];
if(referenceId != "")
{
// delete the physics object
mEngine->removeRigidBody(referenceId);
mEngine->deleteRigidBody(referenceId);
// create a new physics object
mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation,
0, 0, true, placeable);
// update other scene managers if they have the referenceId
// FIXME: rotation or scale not updated
moveSceneNodeImpl(sceneNodeName, referenceId, position);
}
}
// FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects
void PhysicsSystem::moveObject(const std::string &sceneNodeName,
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation)
{
mEngine->adjustRigidBody(mEngine->getRigidBody(sceneNodeName, true /*raycasting*/),
position, rotation);
}
void PhysicsSystem::moveSceneNodeImpl(const std::string sceneNodeName,
const std::string referenceId, const Ogre::Vector3 &position)
{
std::map<Ogre::SceneManager *, CSVRender::SceneWidget *>::const_iterator iter = mSceneWidgets.begin();
for(; iter != mSceneWidgets.end(); ++iter)
{
std::string name = refIdToSceneNode(referenceId, (*iter).first);
if(name != sceneNodeName && (*iter).first->hasSceneNode(name))
{
(*iter).first->getSceneNode(name)->setPosition(position);
}
}
}
void PhysicsSystem::moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position)
{
moveSceneNodeImpl(sceneNodeName, sceneNodeToRefId(sceneNodeName), position);
}
void PhysicsSystem::addHeightField(Ogre::SceneManager *sceneManager,
float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts)
{
std::string name = "HeightField_"
+ QString::number(x).toStdString() + "_" + QString::number(y).toStdString();
if(mTerrain.find(name) == mTerrain.end())
mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts);
mTerrain.insert(std::pair<std::string, Ogre::SceneManager *>(name, sceneManager));
}
void PhysicsSystem::removeHeightField(Ogre::SceneManager *sceneManager, int x, int y)
{
std::string name = "HeightField_"
+ QString::number(x).toStdString() + "_" + QString::number(y).toStdString();
if(mTerrain.count(name) == 1)
mEngine->removeHeightField(x, y);
std::multimap<std::string, Ogre::SceneManager *>::iterator iter = mTerrain.begin();
for(; iter != mTerrain.end(); ++iter)
{
if((*iter).second == sceneManager)
{
mTerrain.erase(iter);
break;
}
}
}
// sceneMgr: to lookup the scene node name from the object's referenceId
// camera: primarily used to get the visibility mask for the viewport
//
// returns the found object's scene node name and its position in the world space
//
// WARNING: far clip distance is a global setting, if it changes in future
// this method will need to be updated
std::pair<std::string, Ogre::Vector3> PhysicsSystem::castRay(float mouseX,
float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera)
{
// NOTE: there could be more than one camera for the scene manager
// TODO: check whether camera belongs to sceneMgr
if(!sceneMgr || !camera || !camera->getViewport())
return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: this should be an exception
// using a really small value seems to mess up with the projections
float nearClipDistance = camera->getNearClipDistance(); // save existing
camera->setNearClipDistance(10.0f); // arbitrary number
Ogre::Ray ray = camera->getCameraToViewportRay(mouseX, mouseY);
camera->setNearClipDistance(nearClipDistance); // restore
Ogre::Vector3 from = ray.getOrigin();
CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance();
float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat();
Ogre::Vector3 to = ray.getPoint(farClipDist);
btVector3 _from, _to;
_from = btVector3(from.x, from.y, from.z);
_to = btVector3(to.x, to.y, to.z);
uint32_t visibilityMask = camera->getViewport()->getVisibilityMask();
bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain);
bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference);
Ogre::Vector3 norm; // not used
std::pair<std::string, float> result =
mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm);
// result.first is the object's referenceId
if(result.first == "")
return std::make_pair("", Ogre::Vector3(0,0,0));
else
{
std::string name = refIdToSceneNode(result.first, sceneMgr);
if(name == "")
name = result.first;
else
name = refIdToSceneNode(result.first, sceneMgr);
return std::make_pair(name, ray.getPoint(farClipDist*result.second));
}
}
std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr)
{
return mRefIdToSceneNode[referenceId][sceneMgr];
}
std::string PhysicsSystem::sceneNodeToRefId(std::string sceneNodeName)
{
return mSceneNodeToRefId[sceneNodeName];
}
void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget *sceneWidget)
{
mSceneWidgets[sceneMgr] = sceneWidget;
mEngine->createDebugDraw(sceneMgr);
}
std::map<Ogre::SceneManager*, CSVRender::SceneWidget *> PhysicsSystem::sceneWidgets()
{
return mSceneWidgets;
}
void PhysicsSystem::removeSceneManager(Ogre::SceneManager *sceneMgr)
{
mEngine->removeDebugDraw(sceneMgr);
mSceneWidgets.erase(sceneMgr);
}
Ogre::SceneManager *PhysicsSystem::findSceneManager(std::string sceneNodeName)
{
std::map<Ogre::SceneManager *, CSVRender::SceneWidget *>::const_iterator iter = mSceneWidgets.begin();
for(; iter != mSceneWidgets.end(); ++iter)
{
if((*iter).first->hasSceneNode(sceneNodeName))
{
return (*iter).first;
}
}
return NULL;
}
void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr)
{
// FIXME: should check if sceneMgr is in the list
if(!sceneMgr)
return;
CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance();
if(!(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false))
{
std::cerr << "Turn on mouse-picking debug option to see collision shapes." << std::endl;
return;
}
mEngine->toggleDebugRendering(sceneMgr);
mEngine->stepDebug(sceneMgr);
}
}

@ -1,94 +0,0 @@
#ifndef CSV_WORLD_PHYSICSSYSTEM_H
#define CSV_WORLD_PHYSICSSYSTEM_H
#include <string>
#include <map>
namespace Ogre
{
class Vector3;
class Quaternion;
class SceneManager;
class Camera;
}
namespace OEngine
{
namespace Physic
{
class PhysicEngine;
}
}
namespace CSVRender
{
class SceneWidget;
}
namespace CSVWorld
{
class PhysicsSystem
{
std::map<std::string, std::string> mSceneNodeToRefId;
std::map<std::string, std::map<Ogre::SceneManager *, std::string> > mRefIdToSceneNode;
std::map<std::string, std::string> mSceneNodeToMesh;
std::map<Ogre::SceneManager*, CSVRender::SceneWidget *> mSceneWidgets;
OEngine::Physic::PhysicEngine* mEngine;
std::multimap<std::string, Ogre::SceneManager *> mTerrain;
public:
PhysicsSystem();
~PhysicsSystem();
void addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene);
void removeSceneManager(Ogre::SceneManager *sceneMgr);
void addObject(const std::string &mesh,
const std::string &sceneNodeName, const std::string &referenceId, float scale,
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
bool placeable=false);
void removeObject(const std::string &sceneNodeName);
void removePhysicsObject(const std::string &sceneNodeName);
void replaceObject(const std::string &sceneNodeName,
float scale, const Ogre::Vector3 &position,
const Ogre::Quaternion &rotation, bool placeable=false);
void moveObject(const std::string &sceneNodeName,
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation);
void moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position);
void addHeightField(Ogre::SceneManager *sceneManager,
float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts);
void removeHeightField(Ogre::SceneManager *sceneManager, int x, int y);
void toggleDebugRendering(Ogre::SceneManager *sceneMgr);
// return the object's SceneNode name and position for the given SceneManager
std::pair<std::string, Ogre::Vector3> castRay(float mouseX,
float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera);
std::string sceneNodeToRefId(std::string sceneNodeName);
// for multi-scene manager per physics engine
std::map<Ogre::SceneManager*, CSVRender::SceneWidget *> sceneWidgets();
private:
void moveSceneNodeImpl(const std::string sceneNodeName,
const std::string referenceId, const Ogre::Vector3 &position);
void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position);
std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr);
Ogre::SceneManager *findSceneManager(std::string sceneNodeName);
};
}
#endif // CSV_WORLD_PHYSICSSYSTEM_H

@ -111,6 +111,12 @@ CSMDoc::Document& CSVWorld::CommandDelegate::getDocument() const
return mDocument;
}
CSMWorld::ColumnBase::Display CSVWorld::CommandDelegate::getDisplayTypeFromIndex(const QModelIndex &index) const
{
int rawDisplay = index.data(CSMWorld::ColumnBase::Role_Display).toInt();
return static_cast<CSMWorld::ColumnBase::Display>(rawDisplay);
}
void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const
{
@ -146,7 +152,17 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode
QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
return createEditor (parent, option, index, CSMWorld::ColumnBase::Display_None);
CSMWorld::ColumnBase::Display display = getDisplayTypeFromIndex(index);
// This createEditor() method is called implicitly from tables.
// For boolean values in tables use the default editor (combobox).
// Checkboxes is looking ugly in the table view.
// TODO: Find a better solution?
if (display == CSMWorld::ColumnBase::Display_Boolean)
{
return QStyledItemDelegate::createEditor(parent, option, index);
}
return createEditor (parent, option, index, display);
}
QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option,

@ -124,6 +124,8 @@ namespace CSVWorld
CSMDoc::Document& getDocument() const;
CSMWorld::ColumnBase::Display getDisplayTypeFromIndex(const QModelIndex &index) const;
virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const;

@ -20,10 +20,9 @@ set(GAME_HEADER
source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
actors objects renderinginterface localmap occlusionquery water shadows
characterpreview globalmap ripplesimulation refraction
terrainstorage renderconst effectmanager weaponanimation
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage
)
add_openmw_dir (mwinput
@ -31,7 +30,7 @@ add_openmw_dir (mwinput
)
add_openmw_dir (mwgui
textinput widgets race class birth review windowmanagerimp console dialogue
layout textinput widgets race class birth review windowmanagerimp console dialogue
windowbase statswindow messagebox journalwindow charactercreation
mapwindow windowpinnablebase tooltips scrollwindow bookwindow
formatting inventorywindow container hud countdialog tradewindow settingswindow
@ -61,12 +60,16 @@ add_openmw_dir (mwsound
)
add_openmw_dir (mwworld
refdata worldimp physicssystem scene globals class action nullaction actionteleport
refdata worldimp scene globals class action nullaction actionteleport
containerstore actiontalk actiontake manualref player cellfunctors failedaction
cells localscripts customdata weather inventorystore ptr actionopen actionread
cells localscripts customdata inventorystore ptr actionopen actionread
actionequip timestamp actionalchemy cellstore actionapply actioneat
esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
contentloader esmloader actiontrap cellreflist projectilemanager cellref
contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager
)
add_openmw_dir (mwphysics
physicssystem trace collisiontype actor convert
)
add_openmw_dir (mwclass
@ -75,10 +78,11 @@ add_openmw_dir (mwclass
)
add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
mechanicsmanagerimp stat creaturestats magiceffects movement
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
character actors objects aistate
)
add_openmw_dir (mwstate
@ -92,9 +96,9 @@ add_openmw_dir (mwbase
# Main executable
if (ANDROID)
set(BOOST_COMPONENTS system filesystem program_options thread wave atomic)
set(BOOST_COMPONENTS system filesystem program_options thread atomic)
else ()
set(BOOST_COMPONENTS system filesystem program_options thread wave)
set(BOOST_COMPONENTS system filesystem program_options thread)
endif ()
if(WIN32)
@ -122,36 +126,27 @@ endif ()
include_directories(${SOUND_INPUT_INCLUDES})
target_link_libraries(openmw
${OENGINE_LIBRARY}
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES}
${OPENSCENEGRAPH_LIBRARIES}
${Boost_LIBRARIES}
${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY}
${BULLET_LIBRARIES}
${MYGUI_LIBRARIES}
${SDL2_LIBRARY}
${MYGUI_PLATFORM_LIBRARIES}
"ogre-ffmpeg-videoplayer"
"osg-ffmpeg-videoplayer"
"oics"
"sdl4ogre"
components
)
if (ANDROID)
target_link_libraries(openmw
${OGRE_STATIC_PLUGINS}
EGL
android
log
dl
MyGUI.OgrePlatform
MyGUIEngineStatic
Plugin_StrangeButtonStatic
cpufeatures
BulletCollision
BulletDynamics
LinearMath
)
endif (ANDROID)

@ -25,7 +25,7 @@
/// \namespace MWRender
/// \ingroup openmw
/// \brief Rendering via Ogre
/// \brief Rendering
/// \namespace MWWorld
/// \ingroup openmw

@ -3,24 +3,29 @@
#include <stdexcept>
#include <iomanip>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <boost/filesystem/fstream.hpp>
#include <MyGUI_WidgetManager.h>
#include <osgViewer/ViewerEventHandlers>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <SDL.h>
#include <openengine/misc/rng.hpp>
#include <components/misc/rng.hpp>
#include <components/vfs/manager.hpp>
#include <components/vfs/registerarchives.hpp>
#include <components/sdlutil/sdlgraphicswindow.hpp>
#include <components/sdlutil/imagetosurface.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/texturemanager.hpp>
#include <components/compiler/extensions0.hpp>
#include <components/bsa/resources.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/translation/translation.hpp>
#include <components/nifoverrides/nifoverrides.hpp>
#include <components/nifbullet/bulletnifloader.hpp>
#include <components/nifogre/ogrenifloader.hpp>
#include <components/esm/loadcell.hpp>
@ -38,6 +43,8 @@
#include "mwworld/player.hpp"
#include "mwworld/worldimp.hpp"
#include "mwrender/vismask.hpp"
#include "mwclass/classes.hpp"
#include "mwdialogue/dialoguemanagerimp.hpp"
@ -66,23 +73,11 @@ void OMW::Engine::executeLocalScripts()
localScripts.setIgnore (MWWorld::Ptr());
}
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
{
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame, paused);
MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame);
}
return true;
}
bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
double OMW::Engine::frame(float frametime)
{
try
{
float frametime = evt.timeSinceLastFrame;
mStartTick = mViewer->getStartTick();
mEnvironment.setFrameDuration (frametime);
// update input
@ -90,8 +85,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
// When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug.
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures.
if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible())
return true;
//if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible())
// return true;
// sound
if (mUseSound)
@ -99,6 +94,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
// GUI active? Most game processing will be paused, but scripts still run.
bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode();
if (!guiActive)
mSimulationTime += frametime;
// Main menu opened? Then scripts are also paused.
bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu);
@ -106,6 +103,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
// update game state
MWBase::Environment::get().getStateManager()->update (frametime);
osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick();
if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_Running)
{
@ -127,15 +125,17 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
MWBase::Environment::get().getWorld()->advanceTime(
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
}
osg::Timer_t afterScriptTick = osg::Timer::instance()->tick();
// update actors
osg::Timer_t beforeMechanicsTick = osg::Timer::instance()->tick();
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
MWBase::Environment::get().getMechanicsManager()->update(frametime,
guiActive);
}
osg::Timer_t afterMechanicsTick = osg::Timer::instance()->tick();
if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_Running)
@ -146,37 +146,51 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
}
// update world
osg::Timer_t beforePhysicsTick = osg::Timer::instance()->tick();;
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
MWBase::Environment::get().getWorld()->update(frametime, guiActive);
}
osg::Timer_t afterPhysicsTick = osg::Timer::instance()->tick();
// update GUI
MWBase::Environment::get().getWindowManager()->onFrame(frametime);
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
Ogre::RenderWindow* window = mOgre->getWindow();
unsigned int tri, batch;
MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch);
MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch);
#if 0
MWBase::Environment::get().getWindowManager()->wmUpdateFps(fps);
#endif
MWBase::Environment::get().getWindowManager()->update();
}
int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
osg::Stats* stats = mViewer->getViewerStats();
stats->setAttribute(frameNumber, "script_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeScriptTick));
stats->setAttribute(frameNumber, "script_time_taken", osg::Timer::instance()->delta_s(beforeScriptTick, afterScriptTick));
stats->setAttribute(frameNumber, "script_time_end", osg::Timer::instance()->delta_s(mStartTick, afterScriptTick));
stats->setAttribute(frameNumber, "mechanics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeMechanicsTick));
stats->setAttribute(frameNumber, "mechanics_time_taken", osg::Timer::instance()->delta_s(beforeMechanicsTick, afterMechanicsTick));
stats->setAttribute(frameNumber, "mechanics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterMechanicsTick));
stats->setAttribute(frameNumber, "physics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforePhysicsTick));
stats->setAttribute(frameNumber, "physics_time_taken", osg::Timer::instance()->delta_s(beforePhysicsTick, afterPhysicsTick));
stats->setAttribute(frameNumber, "physics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterPhysicsTick));
}
catch (const std::exception& e)
{
std::cerr << "Error in framelistener: " << e.what() << std::endl;
}
return true;
return mSimulationTime;
}
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
: mEncoding(ToUTF8::WINDOWS_1252)
: mWindow(NULL)
, mEncoding(ToUTF8::WINDOWS_1252)
, mEncoder(NULL)
, mOgre (0)
, mVerboseScripts (false)
, mSkipMenu (false)
, mUseSound (true)
@ -191,10 +205,10 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mFSStrict (false)
, mScriptBlacklistUse (true)
, mNewGame (false)
, mSimulationTime(0.0)
, mCfgMgr(configurationManager)
{
OEngine::Misc::Rng::init();
std::srand ( static_cast<unsigned int>(std::time(NULL)) );
Misc::Rng::init();
MWClass::registerClasses();
Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK;
@ -206,31 +220,28 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError()));
}
}
mStartTick = osg::Timer::instance()->tick();
}
OMW::Engine::~Engine()
{
if (mOgre)
mOgre->restoreWindowGammaRamp();
mEnvironment.cleanup();
delete mScriptContext;
delete mOgre;
SDL_Quit();
}
mScriptContext = NULL;
// add resources directory
// \note This function works recursively.
mResourceSystem.reset();
void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path)
{
mOgre->getRoot()->addResourceLocation (path.string(), "FileSystem",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
}
mViewer = NULL;
void OMW::Engine::addZipResource (const boost::filesystem::path& path)
{
mOgre->getRoot()->addResourceLocation (path.string(), "Zip",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, false);
if (mWindow)
{
SDL_DestroyWindow(mWindow);
mWindow = NULL;
}
SDL_Quit();
}
void OMW::Engine::enableFSStrict(bool fsStrict)
@ -299,71 +310,146 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath);
// load nif overrides
NifOverrides::Overrides nifOverrides;
std::string transparencyOverrides = "/transparency-overrides.cfg";
std::string materialOverrides = "/material-overrides.cfg";
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + transparencyOverrides))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + transparencyOverrides);
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + transparencyOverrides))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + transparencyOverrides);
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + materialOverrides))
nifOverrides.loadMaterialOverrides(mCfgMgr.getLocalPath().string() + materialOverrides);
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + materialOverrides))
nifOverrides.loadMaterialOverrides(mCfgMgr.getGlobalPath().string() + materialOverrides);
return settingspath;
}
void OMW::Engine::prepareEngine (Settings::Manager & settings)
void OMW::Engine::createWindow(Settings::Manager& settings)
{
mEnvironment.setStateManager (
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
int screen = settings.getInt("screen", "Video");
int width = settings.getInt("resolution x", "Video");
int height = settings.getInt("resolution y", "Video");
bool fullscreen = settings.getBool("fullscreen", "Video");
bool windowBorder = settings.getBool("window border", "Video");
bool vsync = settings.getBool("vsync", "Video");
int antialiasing = settings.getInt("antialiasing", "Video");
std::string renderSystem = settings.getString("render system", "Video");
if (renderSystem == "")
int pos_x = SDL_WINDOWPOS_CENTERED_DISPLAY(screen),
pos_y = SDL_WINDOWPOS_CENTERED_DISPLAY(screen);
if(fullscreen)
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
renderSystem = "Direct3D9 Rendering Subsystem";
#else
renderSystem = "OpenGL Rendering Subsystem";
#endif
pos_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen);
pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen);
}
mOgre = new OEngine::Render::OgreRenderer;
Uint32 flags = SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE;
if(fullscreen)
flags |= SDL_WINDOW_FULLSCREEN;
if (!windowBorder)
flags |= SDL_WINDOW_BORDERLESS;
mOgre->configure(
mCfgMgr.getLogPath().string(),
renderSystem,
Settings::Manager::getString("opengl rtt mode", "Video"));
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
settings.getBool("minimize on focus loss", "Video") ? "1" : "0");
if (antialiasing > 0)
{
if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0)
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0)
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
}
while (!mWindow)
{
mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags);
if (!mWindow)
{
// Try with a lower AA
if (antialiasing > 0)
{
std::cout << "Note: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2 << std::endl;
antialiasing /= 2;
Settings::Manager::setInt("antialiasing", "Video", antialiasing);
if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0)
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
continue;
}
else
{
std::stringstream error;
error << "Failed to create SDL window: " << SDL_GetError() << std::endl;
throw std::runtime_error(error.str());
}
}
}
// This has to be added BEFORE MyGUI is initialized, as it needs
// to find core.xml here.
setWindowIcon();
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
SDL_GetWindowPosition(mWindow, &traits->x, &traits->y);
SDL_GetWindowSize(mWindow, &traits->width, &traits->height);
traits->windowName = SDL_GetWindowTitle(mWindow);
traits->windowDecoration = !(SDL_GetWindowFlags(mWindow)&SDL_WINDOW_BORDERLESS);
traits->screenNum = SDL_GetWindowDisplayIndex(mWindow);
// FIXME: Some way to get these settings back from the SDL window?
traits->red = 8;
traits->green = 8;
traits->blue = 8;
traits->alpha = 8;
traits->depth = 24;
traits->stencil = 8;
traits->vsync = vsync;
traits->doubleBuffer = true;
traits->inheritedWindowData = new SDLUtil::GraphicsWindowSDL2::WindowData(mWindow);
osg::ref_ptr<SDLUtil::GraphicsWindowSDL2> graphicsWindow = new SDLUtil::GraphicsWindowSDL2(traits);
if(!graphicsWindow->valid()) throw std::runtime_error("Failed to create GraphicsContext");
osg::ref_ptr<osg::Camera> camera = mViewer->getCamera();
camera->setGraphicsContext(graphicsWindow);
camera->setViewport(0, 0, width, height);
mViewer->realize();
}
void OMW::Engine::setWindowIcon()
{
boost::filesystem::ifstream windowIconStream;
std::string windowIcon = (mResDir / "mygui" / "openmw.png").string();
windowIconStream.open(windowIcon);
if (windowIconStream.fail())
std::cerr << "Failed to open " << windowIcon << std::endl;
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!reader)
{
std::cerr << "Failed to read window icon, no png readerwriter found" << std::endl;
return;
}
osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream);
if (!result.success())
std::cerr << "Failed to read " << windowIcon << ": " << result.message() << std::endl;
else
{
osg::ref_ptr<osg::Image> image = result.getImage();
SDL_Surface* surface = SDLUtil::imageToSurface(image, true);
SDL_SetWindowIcon(mWindow, surface);
SDL_FreeSurface(surface);
}
}
addResourcesDirectory(mCfgMgr.getCachePath ().string());
void OMW::Engine::prepareEngine (Settings::Manager & settings)
{
mEnvironment.setStateManager (
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
addResourcesDirectory(mResDir / "mygui");
addResourcesDirectory(mResDir / "water");
addResourcesDirectory(mResDir / "shadows");
addResourcesDirectory(mResDir / "materials");
createWindow(settings);
OEngine::Render::WindowSettings windowSettings;
windowSettings.fullscreen = settings.getBool("fullscreen", "Video");
windowSettings.window_border = settings.getBool("window border", "Video");
windowSettings.window_x = settings.getInt("resolution x", "Video");
windowSettings.window_y = settings.getInt("resolution y", "Video");
windowSettings.screen = settings.getInt("screen", "Video");
windowSettings.vsync = settings.getBool("vsync", "Video");
windowSettings.icon = "openmw.png";
std::string aa = settings.getString("antialiasing", "Video");
windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0";
osg::ref_ptr<osg::Group> rootNode (new osg::Group);
mViewer->setSceneData(rootNode);
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
settings.getBool("minimize on focus loss", "Video") ? "1" : "0");
mVFS.reset(new VFS::Manager(mFSStrict));
mOgre->createWindow("OpenMW", windowSettings);
VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true);
Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict);
mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get()));
mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true);
osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST;
osg::Texture::FilterMode mag = osg::Texture::LINEAR;
if (Settings::Manager::getString("texture filtering", "General") == "trilinear")
min = osg::Texture::LINEAR_MIPMAP_LINEAR;
int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General");
mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy);
// Create input and UI first to set up a bootstrapping environment for
// showing a loading screen and keeping the window responsive while doing so
@ -390,29 +476,32 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
else
gameControllerdb = ""; //if it doesn't exist, pass in an empty string
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab);
// FIXME: shouldn't depend on Engine
MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab);
mEnvironment.setInputManager (input);
MWGui::WindowManager* window = new MWGui::WindowManager(
mExtensions, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap);
std::string myguiResources = (mResDir / "mygui").string();
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
guiRoot->setNodeMask(MWRender::Mask_GUI);
rootNode->addChild(guiRoot);
MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(),
mCfgMgr.getLogPath().string() + std::string("/"), myguiResources,
mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap);
mEnvironment.setWindowManager (window);
// Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
mOgre->setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General"));
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
if (!mSkipMenu)
{
std::string logo = mFallbackMap["Movies_Company_Logo"];
if (!logo.empty())
window->playVideo(logo, 1);
window->playVideo(logo, true);
}
// Create the world
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(),
mFileCollections, mContentFiles, mEncoder, mFallbackMap,
mActivationDistanceOverride, mCellName, mStartupScript));
MWBase::Environment::get().getWorld()->setupPlayer();
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
@ -443,8 +532,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setJournal (new MWDialogue::Journal);
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
mOgre->getRoot()->addFrameListener (this);
// scripts
if (mCompileAll)
{
@ -468,18 +555,83 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
}
}
class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
{
public:
WriteScreenshotToFileOperation(const std::string& screenshotPath, const std::string& screenshotFormat)
: mScreenshotPath(screenshotPath)
, mScreenshotFormat(screenshotFormat)
{
}
virtual void operator()(const osg::Image& image, const unsigned int context_id)
{
// Count screenshots.
int shotCount = 0;
// Find the first unused filename with a do-while
std::ostringstream stream;
do
{
// Reset the stream
stream.str("");
stream.clear();
stream << mScreenshotPath << "/screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << mScreenshotFormat;
} while (boost::filesystem::exists(stream.str()));
boost::filesystem::ofstream outStream;
outStream.open(boost::filesystem::path(stream.str()), std::ios::binary);
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(mScreenshotFormat);
if (!readerwriter)
{
std::cerr << "Can't write screenshot, no '" << mScreenshotFormat << "' readerwriter found" << std::endl;
return;
}
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
if (!result.success())
{
std::cerr << "Can't write screenshot: " << result.message() << std::endl;
}
}
private:
std::string mScreenshotPath;
std::string mScreenshotFormat;
};
// Initialise and enter main loop.
void OMW::Engine::go()
{
assert (!mContentFiles.empty());
assert (!mOgre);
mViewer = new osgViewer::Viewer;
osg::ref_ptr<osgViewer::StatsHandler> statshandler = new osgViewer::StatsHandler;
statshandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F3);
statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
"script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000);
statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
"mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000);
statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
"physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000);
mViewer->addEventHandler(statshandler);
Settings::Manager settings;
std::string settingspath;
settingspath = loadSettings (settings);
mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(new WriteScreenshotToFileOperation(mCfgMgr.getUserDataPath().string(),
Settings::Manager::getString("screenshot format", "General")));
mViewer->addEventHandler(mScreenCaptureHandler);
// Create encoder
ToUTF8::Utf8Encoder encoder (mEncoding);
mEncoder = &encoder;
@ -514,15 +666,17 @@ void OMW::Engine::go()
}
// Start the main rendering loop
Ogre::Timer timer;
while (!MWBase::Environment::get().getStateManager()->hasQuitRequest())
osg::Timer frameTimer;
while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
{
float dt = timer.getMilliseconds()/1000.f;
dt = std::min(dt, 0.2f);
double dt = frameTimer.time_s();
frameTimer.setStartTick();
dt = std::min(dt, 0.2);
timer.reset();
Ogre::Root::getSingleton().renderOneFrame(dt);
double simulationTime = frame(dt);
mViewer->frame(simulationTime);
}
// Save user settings
settings.saveUser(settingspath);
@ -560,24 +714,8 @@ void OMW::Engine::activate()
void OMW::Engine::screenshot()
{
// Count screenshots.
int shotCount = 0;
const std::string& screenshotPath = mCfgMgr.getUserDataPath().string();
std::string format = Settings::Manager::getString("screenshot format", "General");
// Find the first unused filename with a do-while
std::ostringstream stream;
do
{
// Reset the stream
stream.str("");
stream.clear();
stream << screenshotPath << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << format;
} while (boost::filesystem::exists(stream.str()));
mOgre->screenshot(stream.str(), format);
mScreenCaptureHandler->setFramesToCapture(1);
mScreenCaptureHandler->captureNextFrame(*mViewer);
}
void OMW::Engine::setCompileAll (bool all)

@ -1,19 +1,28 @@
#ifndef ENGINE_H
#define ENGINE_H
#include <OgreFrameListener.h>
#include <components/compiler/extensions.hpp>
#include <components/files/collections.hpp>
#include <components/translation/translation.hpp>
#include <components/settings/settings.hpp>
#include <components/nifcache/nifcache.hpp>
#include <osgViewer/Viewer>
#include "mwbase/environment.hpp"
#include "mwworld/ptr.hpp"
namespace Resource
{
class ResourceSystem;
}
namespace VFS
{
class Manager;
}
namespace Compiler
{
class Context;
@ -39,36 +48,34 @@ namespace MWGui
class WindowManager;
}
namespace OEngine
namespace Files
{
namespace GUI
{
class MyGUIManager;
}
namespace Render
{
class OgreRenderer;
}
struct ConfigurationManager;
}
namespace Files
namespace osgViewer
{
struct ConfigurationManager;
class ScreenCaptureHandler;
}
struct SDL_Window;
namespace OMW
{
/// \brief Main engine class, that brings together all the components of OpenMW
class Engine : private Ogre::FrameListener
class Engine
{
SDL_Window* mWindow;
std::auto_ptr<VFS::Manager> mVFS;
std::auto_ptr<Resource::ResourceSystem> mResourceSystem;
MWBase::Environment mEnvironment;
ToUTF8::FromType mEncoding;
ToUTF8::Utf8Encoder* mEncoder;
Files::PathContainer mDataDirs;
std::vector<std::string> mArchives;
boost::filesystem::path mResDir;
OEngine::Render::OgreRenderer *mOgre;
osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
std::string mCellName;
std::vector<std::string> mContentFiles;
bool mVerboseScripts;
@ -98,23 +105,17 @@ namespace OMW
bool mScriptBlacklistUse;
bool mNewGame;
Nif::Cache mNifCache;
osg::Timer_t mStartTick;
double mSimulationTime;
// not implemented
Engine (const Engine&);
Engine& operator= (const Engine&);
/// add resources directory
/// \note This function works recursively.
void addResourcesDirectory (const boost::filesystem::path& path);
/// add a .zip resource
void addZipResource (const boost::filesystem::path& path);
void executeLocalScripts();
virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt);
virtual bool frameStarted (const Ogre::FrameEvent& evt);
/// @return The new simulationTime
double frame (float dt);
/// Load settings from various files, returns the path to the user settings file
std::string loadSettings (Settings::Manager & settings);
@ -122,6 +123,9 @@ namespace OMW
/// Prepare engine for game play
void prepareEngine (Settings::Manager & settings);
void createWindow(Settings::Manager& settings);
void setWindowIcon();
public:
Engine(Files::ConfigurationManager& configurationManager);
virtual ~Engine();

@ -21,17 +21,18 @@
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix))
#define USE_CRASH_CATCHER 1
#else
#define USE_CRASH_CATCHER 0
#endif
#if USE_CRASH_CATCHER
#include <csignal>
extern int cc_install_handlers(int argc, char **argv, int num_signals, int *sigs, const char *logfile, int (*user_info)(char*, char*));
extern int is_debugger_attached(void);
#endif
// for Ogre::macBundlePath
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#include <OSX/macUtils.h>
#endif
#include <boost/version.hpp>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
@ -362,7 +363,7 @@ int main(int argc, char**argv)
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#if USE_CRASH_CATCHER
// Unix crash catcher
if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_attached())
{
@ -374,10 +375,10 @@ int main(int argc, char**argv)
std::cout << "Running in a debugger, not installing crash catcher" << std::endl;
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
// set current dir to bundle path
boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path();
boost::filesystem::current_path(bundlePath);
#ifdef __APPLE__
// FIXME: set current dir to bundle path
//boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path();
//boost::filesystem::current_path(bundlePath);
#endif
engine.reset(new OMW::Engine(cfgMgr));
@ -389,7 +390,7 @@ int main(int argc, char**argv)
}
catch (std::exception &e)
{
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix))
if (!isatty(fileno(stdin)))
#endif
SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL);

@ -6,9 +6,9 @@
#include <list>
#include <stdint.h>
namespace Ogre
namespace osg
{
class Vector3;
class Vec3f;
}
namespace ESM
@ -174,8 +174,8 @@ namespace MWBase
virtual bool toggleAI() = 0;
virtual bool isAIActive() = 0;
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
virtual void getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector<MWWorld::Ptr> &objects) = 0;
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects) = 0;
///return the list of actors which are following the given actor
/**ie AiFollow is active and the target is the actor**/

@ -7,11 +7,6 @@
#include "../mwworld/ptr.hpp"
namespace Ogre
{
class Vector3;
}
namespace MWWorld
{
class CellStore;
@ -125,7 +120,7 @@ namespace MWBase
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified.
///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts.
virtual MWBase::SoundPtr playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId,
virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId,
float volume, float pitch, PlayType type, PlayMode mode, float offset=0) = 0;
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition.
@ -162,7 +157,7 @@ namespace MWBase
virtual void update(float duration) = 0;
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0;
virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) = 0;
virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0;

@ -26,14 +26,6 @@ namespace MyGUI
class UString;
}
namespace OEngine
{
namespace GUI
{
class Layout;
}
}
namespace ESM
{
struct Class;
@ -58,6 +50,8 @@ namespace MWWorld
namespace MWGui
{
class Layout;
class Console;
class SpellWindow;
class TradeWindow;
@ -158,7 +152,7 @@ namespace MWBase
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0;
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0;
virtual void wmUpdateFps(float fps) = 0;
/// Set value for the given ID.
virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0;
@ -184,12 +178,6 @@ namespace MWBase
virtual void changeCell(MWWorld::CellStore* cell) = 0;
///< change the active cell
virtual void setPlayerPos(int cellX, int cellY, const float x, const float y) = 0;
///< set player position in map space
virtual void setPlayerDir(const float x, const float y) = 0;
///< set player view direction in map space
virtual void setFocusObject(const MWWorld::Ptr& focus) = 0;
virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0;
@ -241,7 +229,7 @@ namespace MWBase
virtual void addVisitedLocation(const std::string& name, int x, int y) = 0;
/// Hides dialog and schedules dialog to be deleted.
virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0;
virtual void removeDialog(MWGui::Layout* dialog) = 0;
///Gracefully attempts to exit the topmost GUI mode
/** No guarentee of actually closing the window **/
@ -303,8 +291,6 @@ namespace MWBase
virtual void showSoulgemDialog (MWWorld::Ptr item) = 0;
virtual void frameStarted(float dt) = 0;
virtual void changePointer (const std::string& name) = 0;
virtual void setEnemy (const MWWorld::Ptr& enemy) = 0;
@ -361,6 +347,15 @@ namespace MWBase
virtual void cycleSpell(bool next) = 0;
/// Cycle to next or previous weapon
virtual void cycleWeapon(bool next) = 0;
// In WindowManager for now since there isn't a VFS singleton
virtual std::string correctIconPath(const std::string& path) = 0;
virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0;
virtual std::string correctTexturePath(const std::string& path) = 0;
virtual void requestMap(std::set<MWWorld::CellStore*> cells) = 0;
virtual void removeCell(MWWorld::CellStore* cell) = 0;
virtual void writeFog(MWWorld::CellStore* cell) = 0;
};
}

@ -9,11 +9,12 @@
#include "../mwworld/ptr.hpp"
namespace Ogre
#include "../mwrender/rendermode.hpp"
namespace osg
{
class Vector2;
class Vector3;
class Quaternion;
class Vec3f;
class Quat;
class Image;
}
@ -78,14 +79,6 @@ namespace MWBase
public:
enum RenderMode
{
Render_CollisionDebug,
Render_Wireframe,
Render_Pathgrid,
Render_BoundingBoxes
};
struct DoorMarker
{
std::string name;
@ -125,8 +118,6 @@ namespace MWBase
virtual void adjustSky() = 0;
virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0;
virtual const MWWorld::Fallback *getFallback () const = 0;
virtual MWWorld::Player& getPlayer() = 0;
@ -145,21 +136,12 @@ namespace MWBase
virtual bool isCellQuasiExterior() const = 0;
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
virtual osg::Vec2f getNorthVector (MWWorld::CellStore* cell) = 0;
///< get north vector for given interior cell
virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector<DoorMarker>& out) = 0;
///< get a list of teleport door markers for a given cell, to be displayed on the local map
virtual void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0;
///< see MWRender::LocalMap::worldToInteriorMapPosition
virtual Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y) = 0;
///< see MWRender::LocalMap::interiorMapToWorldPosition
virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0;
///< see MWRender::LocalMap::isPositionExplored
virtual void setGlobalInt (const std::string& name, int value) = 0;
///< Set value independently from real type.
@ -192,12 +174,6 @@ namespace MWBase
///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells.
virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0;
///< Return a pointer to a liveCellRef with the given Ogre handle.
virtual MWWorld::Ptr searchPtrViaHandle (const std::string& handle) = 0;
///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found
virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0;
///< Search is limited to the active cells.
@ -271,7 +247,7 @@ namespace MWBase
/// Returns a pointer to the object the provided object would hit (if within the
/// specified distance), and the point where the hit occurs. This will attempt to
/// use the "Head" node, or alternatively the "Bip01 Head" node as a basis.
virtual std::pair<MWWorld::Ptr,Ogre::Vector3> getHitContact(const MWWorld::Ptr &ptr, float distance) = 0;
virtual std::pair<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::Ptr &ptr, float distance) = 0;
virtual void adjustPosition (const MWWorld::Ptr& ptr, bool force) = 0;
///< Adjust position after load to be on ground. Must be called after model load.
@ -305,7 +281,7 @@ namespace MWBase
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0;
///< Convert position to cell numbers
virtual void queueMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity) = 0;
virtual void queueMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity) = 0;
///< Queues movement for \a ptr (in local space), to be applied in the next call to
/// doPhysics.
@ -317,7 +293,7 @@ namespace MWBase
/// collisions and gravity.
/// \return Resulting mode
virtual bool toggleRenderMode (RenderMode mode) = 0;
virtual bool toggleRenderMode (MWRender::RenderMode mode) = 0;
///< Toggle a render mode.
///< \return Resulting mode
@ -395,7 +371,7 @@ namespace MWBase
virtual bool isWading(const MWWorld::Ptr &object) const = 0;
///Is the head of the creature underwater?
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0;
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
virtual void togglePOV() = 0;
@ -439,7 +415,7 @@ namespace MWBase
virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) = 0;
///< get Line of Sight (morrowind stupid implementation)
virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) = 0;
virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist) = 0;
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;
@ -455,8 +431,7 @@ namespace MWBase
virtual void reattachPlayerCamera() = 0;
/// \todo this does not belong here
virtual void frameStarted (float dt, bool paused) = 0;
virtual void screenshot (Ogre::Image& image, int w, int h) = 0;
virtual void screenshot (osg::Image* image, int w, int h) = 0;
/// Find default position inside exterior cell specified by name
/// \return false if exterior with given name not exists, true otherwise
@ -503,9 +478,9 @@ namespace MWBase
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
float speed, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) = 0;
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0;
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) = 0;
virtual const std::vector<std::string>& getContentFiles() const = 0;
@ -514,7 +489,7 @@ namespace MWBase
// Are we in an exterior or pseudo-exterior cell and it's night?
virtual bool isDark() const = 0;
virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0;
virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) = 0;
/// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)
/// @note id must be lower case
@ -546,11 +521,11 @@ namespace MWBase
virtual void spawnRandomCreature(const std::string& creatureList) = 0;
/// Spawn a blood effect for \a ptr at \a worldPosition
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0;
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0;
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0;
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects,
const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0;
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
@ -559,7 +534,7 @@ namespace MWBase
virtual bool isInStorm() const = 0;
/// @see MWWorld::WeatherManager::getStormDirection
virtual Ogre::Vector3 getStormDirection() const = 0;
virtual osg::Vec3f getStormDirection() const = 0;
/// Resets all actors in the current active cells to their original location within that cell.
virtual void resetActors() = 0;

@ -11,12 +11,13 @@
#include "../mwworld/cellstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/physicssystem.hpp"
#include "../mwworld/action.hpp"
#include "../mwworld/failedaction.hpp"
#include "../mwworld/nullaction.hpp"
#include "../mwrender/actors.hpp"
#include "../mwphysics/physicssystem.hpp"
#include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp"
#include "../mwgui/tooltips.hpp"
@ -34,12 +35,11 @@ namespace MWClass
void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
{
if (!model.empty()) {
MWRender::Actors& actors = renderingInterface.getActors();
actors.insertActivator(ptr, model);
renderingInterface.getObjects().insertModel(ptr, model, true);
}
}
void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const
void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
if(!model.empty())
physics.addObject(ptr, model);

@ -19,7 +19,7 @@ namespace MWClass
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const;
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::Ptr& ptr) const;
///< \return name (the one that is to be presented to the user; not the internal one);

@ -11,7 +11,7 @@
#include "../mwworld/actiontake.hpp"
#include "../mwworld/actionalchemy.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/physicssystem.hpp"
#include "../mwphysics/physicssystem.hpp"
#include "../mwworld/nullaction.hpp"
#include "../mwrender/objects.hpp"
@ -33,10 +33,9 @@ namespace MWClass
}
}
void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const
void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
if(!model.empty())
physics.addObject(ptr, model, true);
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const

@ -21,7 +21,7 @@ namespace MWClass
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const;
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::Ptr& ptr) const;
///< \return name (the one that is to be presented to the user; not the internal one);

@ -15,7 +15,7 @@
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/physicssystem.hpp"
#include "../mwphysics/physicssystem.hpp"
#include "../mwworld/nullaction.hpp"
#include "../mwworld/containerstore.hpp"
@ -38,10 +38,9 @@ namespace MWClass
}
}
void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const
void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
if(!model.empty())
physics.addObject(ptr, model, true);
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Armor::getModel(const MWWorld::Ptr &ptr) const

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

Loading…
Cancel
Save